C# WPF绑定到子集合
我拥有以下实体:C# WPF绑定到子集合,c#,wpf,binding,C#,Wpf,Binding,我拥有以下实体: public class User { public User() { Roles = new ObservableCollection<Role>(); } public int UserId { get; set; } public string Name { get; set; } public DateTime DateOfBirth { get; set; } public vir
public class User
{
public User()
{
Roles = new ObservableCollection<Role>();
}
public int UserId { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
public int RoleId { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
我需要设置
复选框的IsChecked
属性,以便它代表SelectedUser
角色,这需要做什么?您可以使用如下所示的MultipleBinding和MultipleValueInverter
<Grid>
<Grid.Resources>
<local:RoleValueConverter x:Key="converter"></local:RoleValueConverter>
</Grid.Resources>
<ListBox ItemsSource="{Binding AllRoles}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" >
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="."></Binding>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}" Path="DataContext"></Binding>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
public class RoleValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//values[0] is Role object
//value[1] is UserManagerViewModel
// then you can see if Selected user had Role object return true else return false
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
公共类RoleValueConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
//值[0]是角色对象
//值[1]是UserManagerViewModel
//然后,您可以查看所选用户的角色对象是否返回true,否则返回false
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
假设您希望“检查”所选用户的角色
首先我们回答这个问题,“这取决于什么数据?”答案很简单,取决于角色本身,因此我们写道:
<CheckBox Content="{Binding Name}" IsChecked="{Binding .}"/>
现在很明显,这不是一个错误;因此,我们需要为它编写一个转换器来检查集合。我们可以在这里做一个多值转换器(如@Moji的回答),但是通过依赖属性公开集合,并在创建转换器时绑定可能更容易
<Window.Resources>
<local:CollectionContainsConverter Collection="{Binding SelectedUser.Roles}"/>
</Window.Resources>
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=., Converter={StaticResource CollectionContainsConverter}"/>
和转换器:
public class CollectionContainsConverter : IValueConverter
{
public IEnumerable<object> Collection { get; set; } //This is actually a DP
public object Convert(...)
{
return Collection.Contains(value);
// or possibly, to allow for the Object.Equals override
return Collection.Any(o => o.Equals(value));
}
public object ConvertBack(...)
{
return Binding.DoNothing;
}
}
公共类集合包含转换器:IValueConverter
{
公共IEnumerable集合{get;set;}//这实际上是一个DP
公共对象转换(…)
{
返回集合。包含(值);
//或者,允许对象。等于覆盖
返回集合.Any(o=>o.Equals(value));
}
公共对象转换回(…)
{
不做任何事;
}
}
尚未测试此项,您可能需要使用第二个返回,以便它不会比较引用,并利用Object.Equals
(或您选择的另一个比较器)确定该项是否在列表中。示例中缺少UserManagerViewModel。@Maximus My bad,UserViewModel==UserManagerViewModelWith WPF,您的数据是您的应用程序,而不是UI。UI只是数据的一个非常用户友好的反映。如果您需要知道是否选择了某个对象,那么应该在数据模型上具有该属性。在您的情况下,我会向您的角色对象添加一个IsSelected属性,当SelectedUser发生更改时,我会遍历AllRolles并更新IsSelected属性以匹配所选用户。当然,假设用户可以修改和保存角色,您需要某种方式将其更改传播回SelectedUser
too@Rachel我同意你建议的方法,目前正在努力实施。由于User
和Role
是由Entity Framework
生成的实体,我更喜欢创建一个RoleViewModel
,它将保存角色名和一个IsChecked
属性。@Yoav yes,我同意这个决定:)我本来打算把它包括进去,但是它不适合评论,我不得不花时间写一个答案。我想我可能在某一点上有一个类,它可以简单地向现有对象添加一个IsSelected或IsChecked值,因为这种事情对我来说相当常见。。。不过我现在记不起来了。我想说的是,它的用法类似于ObservableCollection
,但我不记得了。
<Window.Resources>
<local:CollectionContainsConverter Collection="{Binding SelectedUser.Roles}"/>
</Window.Resources>
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=., Converter={StaticResource CollectionContainsConverter}"/>
public class CollectionContainsConverter : IValueConverter
{
public IEnumerable<object> Collection { get; set; } //This is actually a DP
public object Convert(...)
{
return Collection.Contains(value);
// or possibly, to allow for the Object.Equals override
return Collection.Any(o => o.Equals(value));
}
public object ConvertBack(...)
{
return Binding.DoNothing;
}
}