【问题标题】:Two way binding with converter without source modification与转换器的两种方式绑定,无需修改源
【发布时间】:2016-10-23 21:41:38
【问题描述】:

我想使用 linq 分组作为复选框列表视图的项目源

这是我的数据模型:

public class GroupItem
{
   public string name GroupName { get; set; }
   public string boolean GroupItemFlag { get; set; }
}

它查看模型(数据上下文):

...
IEnumerable<GroupItem> _groupItems;

public IEnumerable<IGrouping<string,GroupItem>> Groups
{
   get { return _groupItems.GroupBy(__item=>__item.GroupName); }
}
...

它的视图:

...
<ListView ItemsSource={Binding Groups}>
   <ListView.ItemTemplate>
        <StackPanel Orientation="Horizontal">
            <CheckBox IsChecked="{Binding Converter={StaticResource groupingToBooleanConverter}, Mode=TwoWay}"/>
            <TextBlock Text="{Binding Key}"/>
        </StackPanel>
   </ListView.ItemTemplate>
</ListView>
...

groupingToBooleanConverter 代码:

public class GroupingToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var group = value as IGrouping<string,GroupItem>;
        return group.Any(__item => __item.GroupItemFlag);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // problem here
        // how to set for all group items GroupItemFlag=(bool)value;
    }
}

我不想为此再创建一个类“Group”,所以我使用 IGrouping 和转换器。

是不是我选错了路?

【问题讨论】:

  • 嗨 Denis,这似乎很好,因为您需要组项目并处理组名称的键。
  • 其实这是一个基于意见的问题。反正我会说说我的看法。以您现在遵循的方式进行操作是非常可观的。通常这是在 MVVM 中做事的方式。您将模型、视图模型逻辑和视图分开。从 ViewModel 到 View 的任何转换都可以使用 Converters 轻松实现。但我对最后一句话表示怀疑。为什么要再创建一个类“组”?
  • 我想获得组名的复选框列表视图。如果选中任何一个组元素,则选中复选框。如果 Checkbox 发生变化,则会为所有组项设置 Checkbox 值
  • @ViVi:viewmodel 的职责应该是以易于从视图中消费的方式从模型中公开数据和逻辑。如果您必须编写大量转换器,那么它就不是那么容易消耗了:) GroupingToBooleanConverter.ConvertBack 方法带有应用程序逻辑的味道。理想情况下,您应该只将 UI 逻辑放入转换器中,BooleanToVisibilityConverter 就是最好的例子。我也可以接受某种 EnumToColor 转换器。
  • 这只是一个简单的例子。问题不是关于视图模型的责任。 GroupItem 可能是视图元素。我想通过单个复选框来操作所有组项。

标签: wpf mvvm binding converter


【解决方案1】:

即使没有转换器也可以实现:

<CheckBox IsChecked="{Binding Path=GroupItemFlag, Mode=OneWay}"
          Command="{Binding DataContext.ToogleGroupCommand, ElementName=LayoutRoot}" 
          CommandParameter="{Binding}"/>
void ToogleGroupCommand_Execute(IGrouping<string, GroupItem> group){
    bool newValue = !group.First().GroupItemFlag;
    foreach(var item in group) item.GroupItemFlag = newValue; 
}

如果您不使用 MVVM,则只需处理 Checked 和 Unchecked 事件。

但是,如果您使用的是 MVVM,我强烈建议您按照 ViVi 的建议创建 Group 类:

public MainViewModel()
{
   Groups = _groupItems.GroupBy(i => i.GroupName).Select(i => new GroupViewModel(i.Key, i);
}
public Groups[] Groups {get;}


public class GroupViewModel
{
    public GroupViewModel(string name, IEnumerable<GroupItem> items)
    {
        Items = items;
    }

    public string Name { get; }
    public IEnumerable<GroupItem> Items { get; }


    public bool? IsChecked
    {
        get
        {
            if (Items.All(i => i.GroupItemFlag)) return true;
            if (Items.Any(i => i.GroupItemFlag)) return null;
            return false;
        }
        set
        {
            foreach (var item in Items)
            {
                item.GroupItemFlag = value.GetValueOrDefault();
            }
        }
    }
}

【讨论】:

  • 谢谢你,Liero,这是一个可靠的方法。我假设他们。但我认为,存在最佳实践。
  • 很多时候,代码隐藏中的事件处理程序会让你的生活更轻松。您不需要在代码隐藏中编写应用程序逻辑,您可以从代码隐藏中调用视图模型方法。这不违反 mvvm。如果它对您有帮助,请使用它。
猜你喜欢
  • 1970-01-01
  • 2018-02-08
  • 2017-11-18
  • 1970-01-01
  • 2013-11-29
  • 2014-11-29
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多