c# - 使用 MVVM 的 DataTemplate ListBox 绑定和触发器中的 CheckBox
问题描述
我正在学习如何使用 MVVM 以及如何在 WPF 应用程序中绑定数据。我以这种方式在 XAML 文件中创建了一个自定义 CheckedListBox:
<ListBox x:Name="materialsListBox" ItemsSource="{Binding CustomCheckBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" Content="{Binding Item}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
而且我还希望为我检查的每个 CheckBox 动态显示一个图像。我知道我需要使用 Binding 和 UpdateSourceTrigger 属性,但我不确定如何实现这一点。我应该在此处添加什么以便我的应用程序执行我想要的操作?
<Image HorizontalAlignment="Left" Height="100" Margin="432,146,0,0" VerticalAlignment="Top" Width="100"/>
这是我的 ViewModel 的 C# 代码的一部分:
public class MainViewModel : ViewModelBase
{
private ObservableCollection<CheckedListItem<string>> _customCheckBox;
public ObservableCollection<CheckedListItem<string>> CustomCheckBox
{
set
{
_customCheckBox = value;
OnPropertyChanged();
}
get { return _customCheckBox; }
}
public class CheckedListItem<T> : ViewModelBase
{
private bool _isChecked;
private T _item;
public CheckedListItem()
{
}
public CheckedListItem(T item, bool isChecked = false)
{
item = _item;
isChecked = _isChecked;
}
public T Item
{
set
{
_item = value;
OnPropertyChanged();
}
get { return _item; }
}
public bool IsChecked
{
set
{
_isChecked = value;
OnPropertyChanged();
}
get { return _isChecked; }
}
}
...
感谢您的任何建议。
解决方案
执行 ProperyChanged 事件的一种简单方法是使用 ViewModelBase this.Set 的基本集,因为它会为您引发更改的事件。
为此,我将视图模型和视图拆分为 2 个,一个用于主视图,一个用于组合复选框和图像的视图。你可以用一个像你一样的人来做,但这对我来说更容易。
CheckBox 和图像的视图模型
public class CheckBoxViewModel : ViewModelBase
{
private bool isChecked;
private string imageSource;
private string imageName;
public CheckBoxViewModel(string imageSource, string imageName)
{
this.ImageSource = imageSource;
this.ImageName = imageName;
}
public ICommand Checked => new RelayCommand<string>(this.OnChecked);
private void OnChecked(object imageName)
{
}
public string ImageSource
{
get { return this.imageSource; }
set { this.Set(() => this.ImageSource, ref this.imageSource, value); }
}
public string ImageName
{
get { return this.imageName; }
set { this.Set(() => this.ImageName, ref this.imageName, value); }
}
public bool IsChecked
{
get { return this.isChecked; }
set { this.Set(() => this.IsChecked, ref this.isChecked, value); }
}
}
主窗口视图模型
public class MainViewModel : ViewModelBase
{
private ObservableCollection<CheckBoxViewModel> items = new ObservableCollection<CheckBoxViewModel>();
public ObservableCollection<CheckBoxViewModel> Items => this.items;
public MainViewModel()
{
var view = new CheckBoxViewModel("Image.Jpg", "Image 1");
this.Items.Add(view);
var view2 = new CheckBoxViewModel("Image2.Jpg", "Image 2");
this.Items.Add(view2);
}
}
复选框和图像视图
<UserControl.Resources>
<local:MainViewModel x:Key="MainViewModel" />
<local:MainViewModel x:Key="ViewModel" />
<local:BoolToVisibility x:Key="BoolToVisibility" />
</UserControl.Resources>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="201*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CheckBox Command="{Binding Checked}" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" Content="{Binding ImageName}" />
<Image Grid.Column="1" Source="{Binding ImageSource}" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding IsChecked, Converter={StaticResource BoolToVisibility}}" />
</Grid>
主视图
<Window.Resources>
<local:MainViewModel x:Key="MainViewModel" />
<DataTemplate DataType="{x:Type local:CheckBoxViewModel}">
<local:view/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListView DataContext="{StaticResource MainViewModel}" ItemsSource="{Binding Items}"/>
</Grid>
这样,主视图模型将 CheckBoxViewModels 添加到其项目中,然后主视图自动将子视图添加到列表视图中。
值得注意的是图像可见性是如何翻转的。我使用了一个添加到图像可见性绑定中的值转换器。它将一个真假值转换为一种可见性。
public class BoolToVisibility : IValueConverter
{
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
if ((bool)value)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
return Visibility.Collapsed;
}
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value that is produced by the binding target.</param>
/// <param name="targetType">The type to convert to.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
推荐阅读
- reactjs - 如何使用 React-router 渲染()
- asp.net - 日期时间上的 FluentValidation
- python - 使用 PyQt5 隐藏 QtableView 的 QComboBox 中已选择的值
- java - Maven 无法下载依赖项
- c++ - Visual Studio 2017 是否需要显式移动构造函数声明?
- java - 是 Intellij Idea 上的 Liberty
- php - 没有得到除法的整数余数
- bash - cd 由变量组成的参数由变量组成
- git - .gitignore 文件扩展名,但不是目录名
- outlook - Outlook Web 加载项不支持 Outlook for Mac