WPF,多绑定CSV到复选框列表框,以及MVVM最佳实践

3
我相对于WPF和MVVM的整体概念还比较新,我正在寻求最佳实践建议。我有一个可行的解决方案,但感觉可能错过了一些能够简化整个过程的伟大XAML语法。
我在数据库表中有一个字符串字段,存储为CSV格式,例如"CAT, DOG"。也许我应该在我的实体数据模型中将其作为多对多关系处理,但这是另一个最佳实践讨论。
在我的XAML中,我在包含复选框的ListBox上使用了多绑定。可能选择的域在运行时确定,ListBox使用DataTemplate生成复选框。以下是XAML代码:
    <ListBox Grid.Column="3" Grid.Row="8" Grid.RowSpan="2" Name="brandedProductsListBox" Margin="3" ItemsSource="{Binding Source={StaticResource brandedProductLookup}}" IsSynchronizedWithCurrentItem="True" TabIndex="475">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Margin="3" Content="{Binding Path=BrandedProductName}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">
                <CheckBox.IsChecked>
                    <MultiBinding Converter="{StaticResource brandedProductToBoolean}">
                        <Binding Source="{StaticResource projectsView}" Path="BrandedProducts" />
                        <Binding Path="BrandedProductName" />
                    </MultiBinding>
                </CheckBox.IsChecked>
            </CheckBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>

我使用转换器来检查适当的复选框。我试图让转换器的ConvertBack方法将布尔值转换为我的CSV字符串,但我无法弄清楚如何访问哪个品牌产品名称,因为我只传递了一个布尔值。以下是转换器:

public class BrandedProductToBooleanConverter : IMultiValueConverter
{
    public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) {
            return false;
        }
        else {
            // The bindings passed in (in order) are: the BrandedProducts field for the current project, 
            // and the Branded Product represented by the current CheckBox.
            string brandedProducts = value[0] as string;
            string brandedProduct = value[1] as string;
            return brandedProducts == null ? false :  brandedProducts.Contains(brandedProduct);
        }
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

在选择实体时,Convert能够正确地检查相应的复选框。但是,在添加新实体时,我发现可以使用CheckBox的Checked和UnChecked事件处理程序来向实体写回数据,代码如下:

        private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        if (projectView.IsAddingNew) {
            CheckBox checkBox = sender as CheckBox;
            NewProject project = projectView.CurrentAddItem as NewProject;
            if (project.BrandedProducts == null) {
                project.BrandedProducts = (string)checkBox.Content;
            }
            else {
                project.BrandedProducts += ", " + (string)checkBox.Content;
            }
        }
        e.Handled = true;
    }

    private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
    {
        if (projectView.IsAddingNew) {
            CheckBox checkBox = sender as CheckBox;
            NewProject project = projectView.CurrentAddItem as NewProject;
            if (project.BrandedProducts != null) {
                project.BrandedProducts = project.BrandedProducts.Replace((string)checkBox.Content + ", ", "").Replace(", " + (string)checkBox.Content, "");
            }
        }
        e.Handled = true;
    }

如果您还在跟着我,问题是有没有更好的方法来实现这个。对我而言,使用转换器从实体生成视图,然后使用事件处理程序将视图更新/命令转换回实体,感觉有点像苹果和橙子。使用事件处理程序这种方式修改ViewModel是否违反了MVVM的某些目标呢?
谢谢您提前的建议, 雷
1个回答

1

雷,

如果你还在跟我一起,那么问题是有没有更好的方法来做这件事?

我发现,在 WPF 中,如果你问这个问题,很可能会有更好的方法。与弱弱的 WinForms 相比,有太多的选项。

使用事件处理程序以这种方式修改 ViewModel 是否违反了 MVVM 的某些目标?

在我看来,是的,它违反了 MVVM。你的代码应该没有 ViewModel 代码(除了设置 ViewModel Binding)在你的 Code-behind 中。

你应该让你的事件执行由你的 ViewModel 暴露的 ICommand(例如 Add、Remove)。参见EventToCommand,它可能适用于您的 CheckBox_CheckedCheckBox_UnChecked 事件。

-jberger


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接