英文:
Set WPF ListViewItem format based on item properties
问题
以下是您提供的内容的中文翻译:
虽然有许多与ListBox
一起执行此操作的帖子,但ListView
控件似乎相当难处理。
简而言之,我想要在ListView
中突出显示某些行为“已禁用”,但仍允许用户搜索/查看它们。
在注释掉的XAML部分中,我可以很好地明确设置所有ListViewItem
的Background
。然而,如果我尝试进行绑定,它会失败……尽管它不会给出任何警告并且运行得很好——它只是不起作用。
我可以明确地为每一列创建一个TextBlock
并在那里设置Background
,但这将导致相当多的复制,而我正试图避免这种情况,因为在我的实际示例中有相当多的列。
我尝试设置DataTemplate
,但无法弄清楚如何允许每列发生绑定——我看到的所有示例都是专门绑定到项目属性(在我的情况下是一列)。我需要这样一个模板来为所有列设置样式,但在其他地方指定列内容。
我认为我接近了解决方案,但我在某个地方漏掉了一小部分或者有些东西没有正确连接。
为了简洁起见,要复制的代码如下:
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<ListView Margin="5" VerticalAlignment="Stretch"
SelectionMode="Single" ItemsSource="{Binding Path=Items}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<!--<Setter Property="Background" Value="{Binding Background}" />-->
<!--<Setter Property="Background" Value="Blue" />-->
</Style>
<!--<DataTemplate DataType="{x:Type local:FooItemViewModel}">
<TextBlock Background="{Binding Background}"></TextBlock>
</DataTemplate>-->
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridView.ColumnHeaderContainerStyle>
<Style>
<Setter Property="GridViewColumnHeader.HorizontalContentAlignment" Value="Left" />
<Setter Property="GridViewColumnHeader.Padding" Value="10 0" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="ID" Width="Auto" DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Barcode" Width="Auto" DisplayMemberBinding="{Binding Barcode}" />
<GridViewColumn Header="Check" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Selected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
XAML的后台代码
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private FooViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new FooViewModel();
DataContext = _viewModel;
Loaded += MainWindow_Loaded;
}
public void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_viewModel.Items = new ObservableCollection<FooItemViewModel>
{
new FooItemViewModel { Id = 1, Barcode = "test1"},
new FooItemViewModel { Id = 2, Barcode = "test2", Selected = true},
new FooItemViewModel { Id = 3, Barcode = "test3"},
};
}
}
}
视图模型
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
namespace WpfApp1
{
internal class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void UpdateProperty<T>(ref T toSet, T value, [CallerMemberName] string propertyName = null)
{
if ((toSet == null && value != null) || !toSet.Equals(value))
{
toSet = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
internal class FooItemViewModel : BaseViewModel
{
private int _id;
private string _barcode;
private bool _selected;
public int Id
{
get => _id;
set => UpdateProperty(ref _id, value);
}
public string Barcode
{
get => _barcode;
set => UpdateProperty(ref _barcode, value);
}
public bool Selected
{
get => _selected;
set => UpdateProperty(ref _selected, value);
}
public Color Background => Color.Blue;
}
internal class FooViewModel : BaseViewModel
{
private FooItemViewModel _selectedItem;
private ObservableCollection<FooItemViewModel> _items = new ObservableCollection<FooItemViewModel>();
public FooItemViewModel Selecteditem
{
get => (FooItemViewModel)_selectedItem;
set => UpdateProperty(ref _selectedItem, value);
}
public ObservableCollection<FooItemViewModel> Items
{
get => _items;
set => UpdateProperty(ref _items, value);
}
}
}
希望这可以帮助您理解代码和问题。
英文:
While there are many posts relating to doing this with a ListBox
, the ListView
control is proving quite resistant.
In a nutshell, I'd like to highlight certain rows in the ListView
as 'disabled' but still allow the user to search/see them listed.
In the commented out XAML sections, I can explicitly set the Background
for all ListViewItem
s just fine. However, if I try to bind it, it fails...though it doesn't give any warnings and runs just fine - it simply doesn't work.
I could explicitly create a TextBlock
for each column and set the Background
there but that would result in quite a bit of copypasta which I'm looking to avoid as I've quite a few columns in my real-world example.
I've tried setting a DataTemplate
but can't figure how to allow the bindings to happen per column - all the examples I've seen bind specifically to the item property (in my case, a column). I'd need such a template to set the style for all columns, but specify the column content elsewhere.
I think I'm close but I'm missing some small piece somewhere or have something not wired up correctly.
For berivity, the code to reproduce is as follows;
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<ListView Margin="5" VerticalAlignment="Stretch"
SelectionMode="Single" ItemsSource="{Binding Path=Items}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<!--<Setter Property="Background" Value="{Binding Background}" />-->
<!--<Setter Property="Background" Value="Blue" />-->
</Style>
<!--<DataTemplate DataType="{x:Type local:FooItemViewModel}">
<TextBlock Background="{Binding Background}"></TextBlock>
</DataTemplate>-->
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridView.ColumnHeaderContainerStyle>
<Style>
<Setter Property="GridViewColumnHeader.HorizontalContentAlignment" Value="Left" />
<Setter Property="GridViewColumnHeader.Padding" Value="10 0" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="ID" Width="Auto" DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Barcode" Width="Auto" DisplayMemberBinding="{Binding Barcode}" />
<GridViewColumn Header="Check" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Selected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
Code behind for XAML
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private FooViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new FooViewModel();
DataContext = _viewModel;
Loaded += MainWindow_Loaded;
}
public void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_viewModel.Items = new ObservableCollection<FooItemViewModel>
{
new FooItemViewModel { Id = 1, Barcode = "test1"},
new FooItemViewModel { Id = 2, Barcode = "test2", Selected = true},
new FooItemViewModel { Id = 3, Barcode = "test3"},
};
}
}
}
View Models
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
namespace WpfApp1
{
internal class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void UpdateProperty<T>(ref T toSet, T value, [CallerMemberName] string propertyName = null)
{
if ((toSet == null && value != null) || !toSet.Equals(value))
{
toSet = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
internal class FooItemViewModel : BaseViewModel
{
private int _id;
private string _barcode;
private bool _selected;
public int Id
{
get => _id;
set => UpdateProperty(ref _id, value);
}
public string Barcode
{
get => _barcode;
set => UpdateProperty(ref _barcode, value);
}
public bool Selected
{
get => _selected;
set => UpdateProperty(ref _selected, value);
}
public Color Background => Color.Blue;
}
internal class FooViewModel : BaseViewModel
{
private FooItemViewModel _selectedItem;
private ObservableCollection<FooItemViewModel> _items = new ObservableCollection<FooItemViewModel>();
public FooItemViewModel Selecteditem
{
get => (FooItemViewModel)_selectedItem;
set => UpdateProperty(ref _selectedItem, value);
}
public ObservableCollection<FooItemViewModel> Items
{
get => _items;
set => UpdateProperty(ref _items, value);
}
}
}
答案1
得分: 1
The Background
property should return a Brush
instead of a Color
for the binding to work:
public Brush Background => Brushes.Blue;
英文:
The Background
property should should return a Brush
instead of a Color
for the binding to work:
public Brush Background => Brushes.Blue;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论