WPF - 将 class 与字符串列表绑定到 ListBox
WPF - Binding class with Lists of strings to a ListBox
我在将多个列表绑定到一个列表框时遇到问题。我希望每个列表都有一个不同颜色的不同 DataTemplate。
我有以下型号类
public class Users
{
public Members Members{ get; set; }
}
public class Members
{
public List<string> Moderators { get; set; }
public List<string> Viewers { get; set; }
}
我使用 INotifyPropertyChanged 关注 ViewModel
private Users users;
public Users Users
{
get { return users; }
set
{
users= value;
RaisePropertyChanged("Users");
}
}
我绑定到这个 ListBox
<ListBox ItemsSource="{Binding Users.Members.Viewers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
现在我只有一个列表绑定到列表框。它工作得很好,但我希望其他列表也绑定到同一个列表框。除此之外,我希望版主有一个不同的模板。
我尝试了很多不同的方法,但似乎没有任何效果。
- 为了合并两个列表并将其设置为 ItemsSource,请使用 CompositeCollection。
WPF 可以使用 ItemTemplateSelector 设置不同的模板,但它需要 class 在某些方面有所不同。您的类型是字符串,因此没有任何区别。我的提示是按如下方式创建枚举
枚举成员类型
{
主持人,
查看器
}
并关注 class:
class Person
{
public string Name{get;set;}
public MemberType Type{get;set;}
}
然后改成这个
public class Members
{
public List<Person> Moderators { get; set; }
public List<Person> Viewers { get; set; }
}
并最终在 ItemTemplateSelector
public class TemplateSelector : DataTemplateSelector
{
public DataTemplate ViewerDataTemplate;
public DataTemplate ModeratorDataTemplate;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var member = item as Person;
switch (member.Type)
{
case MemberType.Moderator:
return ModeratorDataTemplate;
case MemberType.Viewer:
return ViewerDataTemplate;
}
return null;
}
}
与其从原始对象中删除名称,不如保留它并根据原始对象指定不同的颜色 class?
Besides that I want that Moderators have a different template.
如果你只有字符串那是不可能的。请记住,列表框最终只能看到一个列表;所以在一个列表中,如何 标记 一个字符串作为版主或查看者?
a different DataTemplate with a different color.
如果只有字符串,我建议您创建包装器 classes,一个用于版主,一个用于观众,然后将字符串投影到要保存的那些 classes 中。那你可以关注我下面的suggestion/example
通过使用复合集合来保存不同的项目(或者实际上可以使用基本 class 列表或接口列表,如果实例具有这种共性的话 ) 然后有专门的数据模板来寻找原始 class,这是可以做到的。
例子
我有两个 class,一个叫 Ships
,一个叫 Passage
。请注意,两个 class 都有一个 Name
属性,但是可以在模板中对其中一个或两个使用 Name
以外的其他内容。
下面我定义了数据模板和我的列表框。
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type c:Ship}">
<TextBlock Text="{Binding Path=Name}"
Foreground="Red" />
</DataTemplate>
<DataTemplate DataType="{x:Type c:Passage}">
<TextBlock Text="{Binding Path=Name}"
Foreground="Blue" />
</DataTemplate>
</Grid.Resources>
<ListBox Name="myListBox"
Height="300"
Width="200"
ItemsSource="{Binding MyCompositeCollection}">
</ListBox>
</Grid>
所以会发生的是我的船是红色的,通道是蓝色的。
这是我在 VM 中的代码:
private CompositeCollection _MyCompositeCollection;
public CompositeCollection MyCompositeCollection
{
get { return _MyCompositeCollection; }
set { _MyCompositeCollection = value; OnPropertyChanged("MyCompositeCollection"); }
}
这里我加载复合集合:
var temp = new CompositeCollection();
Ships.ForEach(sh => temp.Add(sh));
Passages.ForEach(ps => temp.Add(ps));
MyCompositeCollection = temp;
我在将多个列表绑定到一个列表框时遇到问题。我希望每个列表都有一个不同颜色的不同 DataTemplate。
我有以下型号类
public class Users
{
public Members Members{ get; set; }
}
public class Members
{
public List<string> Moderators { get; set; }
public List<string> Viewers { get; set; }
}
我使用 INotifyPropertyChanged 关注 ViewModel
private Users users;
public Users Users
{
get { return users; }
set
{
users= value;
RaisePropertyChanged("Users");
}
}
我绑定到这个 ListBox
<ListBox ItemsSource="{Binding Users.Members.Viewers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
现在我只有一个列表绑定到列表框。它工作得很好,但我希望其他列表也绑定到同一个列表框。除此之外,我希望版主有一个不同的模板。
我尝试了很多不同的方法,但似乎没有任何效果。
- 为了合并两个列表并将其设置为 ItemsSource,请使用 CompositeCollection。
WPF 可以使用 ItemTemplateSelector 设置不同的模板,但它需要 class 在某些方面有所不同。您的类型是字符串,因此没有任何区别。我的提示是按如下方式创建枚举
枚举成员类型 { 主持人, 查看器 }
并关注 class:
class Person
{
public string Name{get;set;}
public MemberType Type{get;set;}
}
然后改成这个
public class Members
{
public List<Person> Moderators { get; set; }
public List<Person> Viewers { get; set; }
}
并最终在 ItemTemplateSelector
public class TemplateSelector : DataTemplateSelector
{
public DataTemplate ViewerDataTemplate;
public DataTemplate ModeratorDataTemplate;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var member = item as Person;
switch (member.Type)
{
case MemberType.Moderator:
return ModeratorDataTemplate;
case MemberType.Viewer:
return ViewerDataTemplate;
}
return null;
}
}
与其从原始对象中删除名称,不如保留它并根据原始对象指定不同的颜色 class?
Besides that I want that Moderators have a different template.
如果你只有字符串那是不可能的。请记住,列表框最终只能看到一个列表;所以在一个列表中,如何 标记 一个字符串作为版主或查看者?
a different DataTemplate with a different color.
如果只有字符串,我建议您创建包装器 classes,一个用于版主,一个用于观众,然后将字符串投影到要保存的那些 classes 中。那你可以关注我下面的suggestion/example
通过使用复合集合来保存不同的项目(或者实际上可以使用基本 class 列表或接口列表,如果实例具有这种共性的话 ) 然后有专门的数据模板来寻找原始 class,这是可以做到的。
例子
我有两个 class,一个叫 Ships
,一个叫 Passage
。请注意,两个 class 都有一个 Name
属性,但是可以在模板中对其中一个或两个使用 Name
以外的其他内容。
下面我定义了数据模板和我的列表框。
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type c:Ship}">
<TextBlock Text="{Binding Path=Name}"
Foreground="Red" />
</DataTemplate>
<DataTemplate DataType="{x:Type c:Passage}">
<TextBlock Text="{Binding Path=Name}"
Foreground="Blue" />
</DataTemplate>
</Grid.Resources>
<ListBox Name="myListBox"
Height="300"
Width="200"
ItemsSource="{Binding MyCompositeCollection}">
</ListBox>
</Grid>
所以会发生的是我的船是红色的,通道是蓝色的。
这是我在 VM 中的代码:
private CompositeCollection _MyCompositeCollection;
public CompositeCollection MyCompositeCollection
{
get { return _MyCompositeCollection; }
set { _MyCompositeCollection = value; OnPropertyChanged("MyCompositeCollection"); }
}
这里我加载复合集合:
var temp = new CompositeCollection();
Ships.ForEach(sh => temp.Add(sh));
Passages.ForEach(ps => temp.Add(ps));
MyCompositeCollection = temp;