Search code examples
wpflistboxdatatemplateitemtemplateitemssource

Binding to 2 Datasources


I want to bind my Datatemplate to 2 Datasources, one datasource that will actually define what is in the ListBox and other that will determine how many ListBoxes are there and what Items in the Listbox are selected\checked.

I have following XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate x:Key="TokenListTemplate">
        <StackPanel Orientation="Horizontal">
            <CheckBox x:Name="chkToken" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}">
                <TextBlock Text="{Binding Path=Text}" />
            </CheckBox>
        </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="ItemTemplate">
        <Border BorderThickness="1">
            <StackPanel Margin="3">
                <TextBlock Text="{Binding Path=Header}"/>
                <ListBox ItemTemplate="{StaticResource TokenListTemplate}" 
                         ItemsSource="{Binding Path=Tokens}" >
                </ListBox>
            </StackPanel>
        </Border>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ListBox ItemTemplate="{StaticResource ItemTemplate}" 
             ItemsSource="{Binding}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

And this is the codebehind

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

        ObservableCollection<DataEntity> _actualObjects;

        List<Token> tokens1 = new List<Token>() 
                                            { 
                                                new Token("1"),                                                     
                                                new Token("2"), 
                                                new Token("3"), 
                                                new Token("4") 
                                            };

        List<Token> tokens2 = new List<Token>() 
                                            { 
                                                new Token("11"),                                                     
                                                new Token("21"), 
                                                new Token("31")
                                            };

        _actualObjects = new ObservableCollection<DataEntity>()
            {
                new DataEntity(tokens1, "A", "1,2,3", 1),  
                new DataEntity(tokens1, "B", "2,3", 1),
                new DataEntity(tokens2, "C", "21,31", 2)
            };


        DataContext = _actualObjects;
    }

    class DataEntity
    {
        public DataEntity(List<Token> tokens, string header, string tokenString, int entityTypeId)
        {
            Tokens = tokens;
            Header = header;
            TokenString = tokenString;
            EntityTypeId = entityTypeId;
        }
        public List<Token> Tokens { get; set; }
        public String Header { get; set; }
        public String TokenString { get; set; }
        public int EntityTypeId { get; set; }

    }

    public class Token
    {
        public bool IsSelected { get; set; }
        public string Text { get; set; }
        public Token(string text)
        {
            this.IsSelected = false;
            this.Text = text;
        }
    }
}

It produces this enter image description here

I don't want to inject token1 or token2 List into DataEntity object so in other words I want DataEntity constructor to be

public DataEntity(string header, string tokenString, int entityTypeId)

Listbox DataTemplate should select

  • tokens1 List as datasource for its LisBoxItems if Dataentity.EntityTypeId = 1
  • tokens2 List as datasource for its LisBoxItemsif DataEntity.EntityTypeId = 2

Also TokenString in DataEntity should be bound to items in the Listbox i.e. if Listbox shows 1 2 3 4 and DataEntity for this listbox has its TokenString value set to "1,2,3" then 1 2 3 should be checked in the listbox enter image description here


Solution

  • I would recommend to create a ViewModel as a layer between your model and the view. In the ViewModel you can arrange the data to fit to the used controls without changing your model.

    So the ViewModel could for example split the tokenString of the DataEntity into a list of tokens.

    Just Google for MVVM (Model-View-ViewModel) for examples and furter explanations or look here on SO (like MVVM: Tutorial from start to finish?).