【问题标题】:TabItem DataTemplate with binding带绑定的 TabItem DataTemplate
【发布时间】:2016-09-08 06:18:58
【问题描述】:

我的应用中有一个TabControl。我希望在我的字典中有尽可能多的TabItems

这是我的字典:

public Dictionary<string , ObservableCollection<PerformanceCounter>> Counters
{
    get { return _Counters; }
}
Dictionary<string, ObservableCollection<PerformanceCounter>> _Counters = new Dictionary<string , ObservableCollection<PerformanceCounter>>();

每个条目都有一个字符串键和 PerformanceCounter 对象的 ObservableCollection。重要的是每个 PerformanceCounter 对象都有属性:CounterName 和 InstanceName - 我需要这两个来显示它们。

现在,我的 XAML:

<TabItem Header="Memory">
    <Grid Name="RAMGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition  Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox Name="RAMListBox" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" ItemsSource="{Binding Memory, Mode=OneWay}" SelectionMode="Multiple" BorderThickness="1" BorderBrush="#FF8B8B8B" SelectionChanged="RAMListBox_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock>
                        <Run Text="{Binding CounterName, Mode=OneWay}" />
                        <Run Text="{Binding InstanceName, Mode=OneWay}" />
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>                                         
        <Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" Click="RAMSelectAllButton_Click" >
            <TextBlock Text="SELECT ALL"/>
        </Button>
        <Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" Click="RAMUnSelectAllButton_Click" >
            <TextBlock Text="UNSELECT ALL"/>
        </Button>
    </Grid>
</TabItem>

这就是我所做的,您可能已经知道,它不起作用。上面的代码只针对我的字典的一个条目,其中的键是“内存”。

在我的代码中,我设置了 DataContext:

this.DataContext = appData.Counters;

appData.Counters 是我一开始介绍的字典。

这是我想要实现的目标: 无论我的字典中有多少条目,我的 TabControl 都会为每个条目显示 TabItem。 每个 TabItem 都有一个 ListBox 和 2 个按钮。我也需要能够访问这些(以清除列表并为每个按钮设置点击事件)。

我真的不知道该怎么做,希望你能帮帮我。

【问题讨论】:

  • 你的字典中的项目数会在运行时改变吗?
  • 不,不会改变
  • 如果有人告诉我如何正确绑定到我的字典,我将不胜感激(即使没有数据模板 - 现在我可以根据需要手动添加尽可能多的 TabItems)。这对我来说最重要。
  • @Arie 我试过了。这就是我所做的:我将 ListBox 绑定到 Counters。然后在我的 textBlock 我这样做: 这个例子是针对我字典中的“处理器”键的。它不起作用 - 列表框为空

标签: c# wpf xaml binding


【解决方案1】:

将 TabControl 绑定到 Dictionary 中的项目:

<Window.Resources>

    <DataTemplate x:Key="templateForTheContent" >
        <StackPanel>
            <ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" 
                     ItemsSource="{Binding Value, Mode=OneWay}"
                     SelectionMode="Multiple"
                         BorderThickness="1" BorderBrush="#FF8B8B8B">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock>
                                    <Run Text="{Binding CounterName, Mode=OneWay}" />
                                    <Run Text="{Binding InstanceName, Mode=OneWay}" />
                        </TextBlock>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="templateForTheHeader" >
        <TextBlock Text="{Binding Key}"/>
    </DataTemplate>

</Window.Resources>
<Grid>
    <TabControl TabStripPlacement="Left"  VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch"
        ItemsSource="{Binding Counters}"
        ContentTemplate="{StaticResource templateForTheContent}"
        ItemTemplate="{StaticResource templateForTheHeader}">
    </TabControl>
</Grid>

现在,字典是不可观察的,因此如果在运行时添加/删除项目,您可以考虑使用类似 ObservableDictionary 的东西

【讨论】:

  • 是否有替代使用 ObservableDictionary 的方法?我尝试使用它,但我得到导致 ObservableDictionary 类代码的异常。也许每次我向字典中添加内容时都可以手动触发更改通知?
  • 当然,您只需要实现 INotifyCollectionChanged-interface。这可以通过继承 List 来完成。不错的副作用:您最终将拥有基本 ObservableCollection 所没有的所有不错的 LINQ 扩展。
  • @Loreno 你确定你必须使用字典吗?有时只使用 ObservableCollection 或其他实现 INotifyCollectionChanged 的​​东西更简单
  • 我稍微改变了我的代码,所以现在我不使用字典了。现在我有 ObservableColection>
  • 我会尝试将上述解决方案应用于我目前的情况,但我希望有人可以帮助我。绑定对我来说真的很难
【解决方案2】:

创建一个包含以下内容的 ViewModel 类:

  1. 你的字典
  2. 按钮的两个 ICommand 实现

然后

  1. 将 ViewModel 类设置为 TabControlDataContext
  2. Counters 设置为 TabControlItemSource
  3. 重用您在 TabItem 中定义的 XAML 代码并将其用作 Tabcontrol.ContentTemplate
  4. 使用 RelativeSource 将按钮的 .Command 绑定到 ViewModel 中的 ICommand

查看示例:

  1. 内容模板:https://wpf.2000things.com/tag/tabcontrol/
  2. ICommand https://stackoverflow.com/a/1468830/4919708
  3. 相对来源:https://stackoverflow.com/a/84317/4919708

【讨论】:

  • 我不使用 MVVM - 我什至不知道它是什么,但我到处都能看到这样的建议,所以最终我必须阅读一些关于它的内容。
【解决方案3】:

正如我在上面的其中一个 cmets 中所说,我将字典更改为:

//list of all counters
        public ObservableCollection<ObservableCollection<PerformanceCounter>> Counters
        {
            get { return _Counters; }
        }
        ObservableCollection<ObservableCollection<PerformanceCounter>> _Counters = new ObservableCollection<ObservableCollection<PerformanceCounter>>();    

我使用@Arie 的解决方案来编写这个 XAML:

            <DataTemplate x:Key="templateForTheContent" >
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition  Height="Auto"/>
                </Grid.RowDefinitions>
                <ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" 
                         ItemsSource="{Binding}"
                         SelectionMode="Multiple"
                             BorderThickness="1" BorderBrush="#FF8B8B8B">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock>
                                        <Run Text="{Binding CounterName, Mode=OneWay}" />
                                        <Run Text="{Binding InstanceName, Mode=OneWay}" />
                            </TextBlock>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
                <Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1"  >
                    <TextBlock Text="SELECT ALL"/>
                </Button>
                <Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" >
                    <TextBlock Text="UNSELECT ALL"/>
                </Button>
            </Grid>
        </DataTemplate>

            <DataTemplate x:Key="templateForTheHeader" >
                <TextBlock Text="{Binding CategoryName}"/>
            </DataTemplate>

        </Window.Resources>

当我在后面的代码中向我的 Class ObservableCollection 添加条目时,它会正确显示尽可能多的选项卡。

现在我有一个新问题:我不知道如何从每个选项卡访问每个列表框。我需要能够读取选定对象的列表。

【讨论】:

    猜你喜欢
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 2018-04-21
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多