Catel MVVM如何在一个ListBox中设置两个不同的Item Source

时间:2014-09-05 11:33:42

标签: c# wpf xaml mvvm catel

我正在尝试创建一个包含扩展程序列表的视图,当我按下以展开其中一个要加载的不同项目源的名称列表时,我想要。到目前为止,我得到的是当我将项目源设置为LineRouteCollection以设置扩展器的标头时,即使我绑定扩展器以显示AllStopsCollection中的名称绑定"名称"显示LineRouteCollection源中的名称,而不是我想要的AllStopsCollection中的名称。你能看看我的代码并告诉我我做错了吗?

<ListBox>
    <ItemsControl ItemsSource="{Binding LineRouteCollection}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Expander Header="{Binding Name}" MinHeight="70">                            
                    <ListBox >
                        <ItemsControl ItemsSource ="{Binding AllStopsCollection}">
                            <TextBlock Text="{Binding Name}"></TextBlock>
                        </ItemsControl>
                    </ListBox>
                </Expander>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ListBox>

编辑:

在我的View模型中,我加载了observable集合(AllStopsCollection&amp; LineRouteCollection),如下所示:

private ObservableCollection<Route> AllLineRoutes;
private ObservableCollection<StopView> AllRouteStops;

//List of all Routes connected to the selected line
public ObservableCollection<Route> LineRouteCollection // Must be property or DP to be bound!
{
    get { return AllLineRoutes; }
    set
    {
        if (Equals(value, AllLineRoutes)) return;
        AllLineRoutes = value;
    }
}


//List of all stops
public ObservableCollection<StopView> AllStopsCollection // Must be property or DP to be bound!
{
    get { return AllRouteStops; }
    set
    {
        if (Equals(value, AllRouteStops)) return;
        AllRouteStops = value;
    }
}

我在类的构造函数中用数据填充集合。我正在正确加载数据,我可以看到它但扩展器扩展后它不会出现在文本框中。

2 个答案:

答案 0 :(得分:1)

您为第一个ItemTemplate提供了ItemsControl,但内部ItemsControl包含一个TextBlock,它只是嵌套在控件中

您还需要为内部控件指定ItemTemplate

<ListBox>
    <ItemsControl ItemsSource="{Binding LineRouteCollection}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Expander Header="{Binding Name}" MinHeight="70">                            
                    <ListBox>
                        <ItemsControl ItemsSource ="{Binding AllStopsCollection}">
                            <ItemsControl.ItemTemplate> <!-- You forgot this ItemTemplate -->
                                <DataTemplate>
                                    <TextBlock Text="{Binding Name}"></TextBlock>
                               </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                   </ListBox>
                </Expander>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ListBox>

否则最内部TextBlock的绑定范围将与内部ItemsControl相同,从而导致您遇到的问题

不确定为什么ItemsControl内有ListBox但是..?您是否希望Expanders中的多个ListBox而不是单个列表项?

这个对我来说很好用:

    <ListBox ItemsSource="{Binding LineRoutes}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Expander Header="{Binding Name}" MinHeight="70">
                    <ListBox ItemsSource ="{Binding AllStops}">
                            <ListBox.ItemTemplate>
                                <!-- You forgot this ItemTemplate -->
                                <DataTemplate>
                                    <TextBlock Text="{Binding Name}"></TextBlock>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                    </ListBox>
                </Expander>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Example of nested expanders in listbox

这就是你想要的吗?

修改

根据您的更新,我可以看到错误是什么

您希望在输出窗口中保持眼睛剥离绑定错误。

AllStopsCollection不是LineRouteCollection的孩子,因此内部控件的DataContext指向的是Route,而不是ViewModel

为了绑定到Stop的集合,您需要确保将绑定指向具有ViewModel的{​​{1}} DataContext的控件。最简单的方法是使用ElementName绑定并绑定到根控件(通常称为LayoutRoot

e.g。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" d:DataContext="{d:DesignInstance wpfApplication1:ViewModel}">
    <Grid Name="LayoutRoot">
        <ListBox ItemsSource="{Binding LineRouteCollection}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Expander Header="{Binding Name}" MinHeight="70">
                        <ListBox ItemsSource ="{Binding DataContext.AllStopsCollection, ElementName=LayoutRoot}"> <!-- Provide an ElementName binding to point to the root Grid and bind to the viewmodels AllStopsCollection (viewmodel is in the DataContext) -->
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding Name}"></TextBlock>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ListBox>
                    </Expander>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

希望有所帮助

唯一需要注意的是,如果你需要操纵一个停止 - 显然,如果你将同一个集合绑定到多个子列表,如果你改变一个Stop项,它将改变每一个的值列表也是因为引用都指向同一个对象

答案 1 :(得分:-1)

这是一种方法,试着变得更有活力。这是一个列表框,我预先定义了3个不同的文本框,并在运行时提供了值。

<ListBox x:Name="ListBox1" HorizontalAlignment="Left" Height="253" Margin="10,28,0,0" VerticalAlignment="Top" Width="734">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid x:Name="grid" Margin="0,2">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="234" />
                                    <ColumnDefinition Width="143" />
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" HorizontalAlignment="Left" Text="{Binding String1}"/>
                                <TextBlock Grid.Column="1" HorizontalAlignment="Left" Text="{Binding String2}" TextTrimming="WordEllipsis"/>
                                <TextBlock Grid.Column="2" HorizontalAlignment="Left" Text="{Binding String3}"/>
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

代码背后:

    public class Class1
    {
        public string String1 { get; set; }
        public string String2 { get; set; }
        public string String3 { get; set; }
    }

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
            ListBox1.Items.Add((new Class1()
            {
                String1 = "Apple",
                String2 = "Car",
                String3 = "Tree"
            }));
    }

如果您想要一个在运行时更具动态性的解决方案,您可以执行以下操作:

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
                Grid WholeGrid = new Grid();
                WholeGrid.HorizontalAlignment = HorizontalAlignment.Left;
                ColumnDefinition colDef1 = new ColumnDefinition();
                ColumnDefinition colDef2 = new ColumnDefinition();
                ColumnDefinition colDef3 = new ColumnDefinition();
                WholeGrid.ColumnDefinitions.Add(colDef1);
                WholeGrid.ColumnDefinitions.Add(colDef2);
                WholeGrid.ColumnDefinitions.Add(colDef3);

                // Create Question Lable
                Label QuestionLabel = new Label();
                QuestionLabel.Content = "Apple";
                Grid.SetRow(QuestionLabel, 0);
                Grid.SetColumn(QuestionLabel, 0);

                // Create Date Picker
                DatePicker newDatePicker = new DatePicker();
                newDatePicker.Width = 200;
                newDatePicker.Height = 20;
                Grid.SetRow(newDatePicker, 0);
                Grid.SetColumn(newDatePicker, 1);

                // Add to Lable and Date Picker
                WholeGrid.Children.Add(QuestionLabel);
                WholeGrid.Children.Add(newDatePicker);
                ListBox1.Items.Add(WholeGrid);
    }