1

I have a problem with binding multiple Lists to a ListBox. I want that every List has a different DataTemplate with a different color.

I have following model classes

public class Users
{
        public Members Members{ get; set; }
}

public class Members
{
        public List<string> Moderators { get; set; }
        public List<string> Viewers { get; set; }
}

I have following ViewModel with INotifyPropertyChanged

private Users users;

public Users Users
{
    get { return users; }
    set
    {
        users= value;
        RaisePropertyChanged("Users");
    }
}

And I'm binding to this ListBox

<ListBox ItemsSource="{Binding Users.Members.Viewers}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
 </ListBox>

Now I only have that one List bound to the ListBox. It works great but I want the other list also bound to the same ListBox. Besides that I want that Moderators have a different template.

I tried many different things but nothing seemed to work.

2 Answers 2

2

Instead of removing the names from the origination object why not keep it and specify different colors based off of the originating class?

Besides that I want that Moderators have a different template.

If you only have strings that is impossible. Remember the listbox ultimately sees only one list; so in one list, how is it possible to tag a string as either moderator or viewer?

a different DataTemplate with a different color.

If there are only strings I suggest you create wrapper classes, one for moderators and one for viewers, then project the strings into those classes to be held. Then you can follow my suggestion/example below.


Via the use of the Composite collection to hold different items (or one could actually use a base class list or a interface list if the instances have that commonality) and then have specialized data templates which look for the originating class, it can be done.

Example

I have two classes one named Ships and one named Passage. Note that both classes both have a Name property, but one could use something other than Name for either or both in the templates.

Below I define the data templates and my listbox.

<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>

So what will happen is that my ships will be red and the passages will be blue. enter image description here


Here is my code in the VM:

private CompositeCollection _MyCompositeCollection;

public CompositeCollection MyCompositeCollection
{
    get { return _MyCompositeCollection; }
    set { _MyCompositeCollection = value; OnPropertyChanged("MyCompositeCollection"); }
}

Here I load the composite collection:

var temp  = new CompositeCollection();

Ships.ForEach(sh => temp.Add(sh));
Passages.ForEach(ps => temp.Add(ps));

MyCompositeCollection = temp;
Sign up to request clarification or add additional context in comments.

2 Comments

Nice explanation! I failed to mention that I can't change the classes that are mentioned in my example because I "inherit" them from a WebAPI. But I can of course create new classes out of the string Lists.
@Shamshiel Don't forget that one can have Partial classes of those WebAPI classes could by defacto could extend the properties as needed.
2
  1. In order to combine two Lists and set it to ItemsSource use CompositeCollection.
  2. WPF can set distinct template by using ItemTemplateSelector but it entails class to be diffrent in some way. Your type is string so it does not differ in any way. My hint is to create enum as follows

    enum MemberType { Moderator, Viewer }


and following class:

class Person
{
    public string Name{get;set;}
    public MemberType Type{get;set;}
}

then change to this

public class Members
    {
        public List<Person> Moderators { get; set; }
        public List<Person> Viewers { get; set; }
    }

and eventually in 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;
        }
    }

3 Comments

Interesting thought. One thing to add maybe, such as showing how one wires in the TemplateSelector into the ListBox in Xaml would be helpful.
I indicated key words like TemplateSelector etc. Everything you can look up on SO. I would like to avoid copying and pasting If such examples already exist.
Thank you for your answer. Sadly I can only mark one of the answers as correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.