首页 > 解决方案 > 使用 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; }
            }
        }
...

感谢您的任何建议。

标签: c#wpfmvvmdata-bindingeventtrigger

解决方案


执行 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;
    }
}

推荐阅读