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>

现在我只有一个列表绑定到列表框。它工作得很好,但我希望其他列表也绑定到同一个列表框。除此之外,我希望版主有一个不同的模板。

我尝试了很多不同的方法,但似乎没有任何效果。

  1. 为了合并两个列表并将其设置为 ItemsSource,请使用 CompositeCollection
  2. 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;