双向绑定转换器,无需修改源

时间:2016-06-22 05:59:09

标签: wpf mvvm binding converter

我想使用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和转换器。

可能是我选择了错误的方式?

1 个答案:

答案 0 :(得分: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();
            }
        }
    }
}