与转换器的两种方式绑定,无需修改源代码
Two way binding with converter without source modification
我想使用 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;
}
}
我不想为此再创建一个 class "Group",所以我使用 IGrouping 和转换器。
可能是我选错方法了?
不用转换器也能实现:
<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 的建议创建组 class:
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();
}
}
}
}
我想使用 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;
}
}
我不想为此再创建一个 class "Group",所以我使用 IGrouping 和转换器。
可能是我选错方法了?
不用转换器也能实现:
<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 的建议创建组 class:
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();
}
}
}
}