TabControl将ItemsSource绑定到具有现有TabItem的List

时间:2017-11-11 04:40:53

标签: c# wpf mvvm

我认为我正在寻找的是MVVM,但我看过的例子并没有帮助,所以基于我的问题的例子应该有所帮助。我已经在TabControl中有内容,所以我无法使用Items collection must be empty before using ItemsSource. ,因为它会抛出异常;

TabControl.Items.Add(newTabItem)

...使用DataTemplate可能需要更多工作,因为必须关闭某些标签页。

我有一个TabControl,其中第一个选项卡包含一个包含人员列表的DataGrid,我希望每当在DataGrid中单击一个项目时,都会创建一个包含该人员详细信息的新选项卡。我想将person对象传递给TabItem&#34; scope / class&#34;并应显示该人的内容。我为人员详细信息TabItem创建了一个<TabControl Name="AttorneysTabControl" Grid.Column="2" Grid.Row="0"> <TabControl.Resources> <DataTemplate x:Key="AttorneyTabHeader"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Attorney.Names}" Margin="2,0,0,0" FontSize="16" VerticalAlignment="Center" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="AttorneyTabContent"> <StackPanel> <TextBlock Text="{Binding Attorney.Names}" /> <TextBlock Text="{Binding Attorney.Age}"/> <ToolBar> <Button ToolTip="">Delete</Button> <Button ToolTip="">Edit</Button> </ToolBar> </StackPanel> </DataTemplate> </TabControl.Resources> <TabItem> <TabItem.Header> <StackPanel Orientation="Horizontal"> <TextBlock Text="Attorneys" Margin="2,0,0,0" FontSize="16" VerticalAlignment="Center" /> </StackPanel> </TabItem.Header> <TabItem.Content> <Grid Background="#FFE5E5E5" Height="Auto"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="5" /> <ColumnDefinition Width="3*" /> </Grid.ColumnDefinitions> ... </Grid> </TabItem.Content> </TabItem> <!-- This part here --> <!-- I want this to repeat. I think I should use a UserControl for this since I want the content to have it's own class --> <TabItem ContentTemplate="{StaticResource AttorneyTabContent}" HeaderTemplate="{StaticResource AttorneyTabHeader}" /> </TabControl> ,您可以在下面看到它;

private List<Record> allItems; // with getter and setter
private List<Record> selectedItems; // with getter and setter

public void onSelect(SelectEvent event) {
    if (null == event || null == event.getObject()) {
        return;
    }
    if (!event.isCtrlKey()) {
        setSelectedItems(new ArrayList<Record>());
    }
    Record item = (Record)event.getObject();
    if (!getSelectedItems().contains(item)) {
        getSelectedItems().add(item);
    }
}

public void onUnselect(UnselectEvent event) {
    if (null == event || null == event.getObject()) {
        return;
    }
    Record item = (Record)event.getObject();
    if (getSelectedItems().contains(item)) {
        getSelectedItems().remove(item);
    }
}

public void deleteSelected() {
    if (getAllItems().isEmpty()) {
        addErrorMessage("listEmpty");
        return;
    }
    if (getSelectedItems().isEmpty()) {
        addErrorMessage("noItemSelected");
        return;
    }
    for (Record item : getSelectedItems()) {
        if (getAllItems().contains(item)) {
            getAllItems().remove(item);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

除非我遗漏了你的要求,否则这不是不可能的。我会说它听起来不是一个好的用户体验,但你比我更了解你的用户和用例。

我把我认为会做你想做的事情放在一起。您需要根据数据进行调整。我希望无论如何都有帮助。请记住,这只是概念代码的证明。

首先是MainWindow的XAML。这里没什么特别的。它最初是一个简单的TabControl托管TabItem Listbox

<Window x:Class="WpfTabControl1.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:local="clr-namespace:WpfTabControl1"
        mc:Ignorable="d"
        Title="TabControl Sample" Height="350" Width="525">
    <Window.Resources>
        <x:Array x:Key="Items" Type="{x:Type local:Item}">
            <local:Item Name="Item A" Value="1" />
            <local:Item Name="Item B" Value="2" />
            <local:Item Name="Item C" Value="3" />
        </x:Array>
    </Window.Resources>
    <Grid>
        <TabControl x:Name="ItemTabControl">
            <TabItem Header="Items">
                <ListBox x:Name="ItemListBox" ItemsSource="{StaticResource Items}"
                         SelectionChanged="ListBox_SelectionChanged" />
            </TabItem>
        </TabControl>
    </Grid>
</Window>

背后的代码是大多数有趣的事情发生的地方。我根据项目的选项卡是否已存在,在事件处理程序中执行以下两项操作之一 - 我创建选项卡或选择选项卡。

public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (ItemListBox.SelectedItem is Item item) {
            // select the tab if one was already created for the item;
            // otherwise, create a new tab for it
            if (TabExists(item.Name, out TabItem tab)) {
                ItemTabControl.SelectedItem = tab;
            }
            else {
                var newItem = new ItemTabItem() {
                    Item = (Item)ItemListBox.SelectedItem
                };

                int newIndex = ItemTabControl.Items.Add(newItem);
                ItemTabControl.SelectedIndex = newIndex;
            }
        }
    }

    bool TabExists(string name, out TabItem tab)
    {
        tab = (from object item in ItemTabControl.Items
               let t = item as ItemTabItem
               where t != null && t.Item.Name == name
               select t).FirstOrDefault();

        return (tab != null);
    }
}

我的ItemTabItem(我知道名字很棒)负责显示Item类实例。这是XAML,后面跟着代码。

<TabItem x:Class="WpfTabControl1.ItemTabItem"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfTabControl1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TextBlock Text="Name" />
        <TextBlock Grid.Row="1" Text="Value" />
        <TextBox Grid.Column="1" Text="{Binding Name, Mode=TwoWay}" />
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Value, Mode=TwoWay}" />
    </Grid>
</TabItem>

现在代码背后。我们可以直接设置DataContext,但属性使它更清晰,并允许我设置标题(可能数据绑定它)。

public partial class ItemTabItem : TabItem
{
    private Item item;

    public ItemTabItem() => InitializeComponent();

    public Item Item
    {
        get => item;
        set
        {
            item = value;
            DataContext = value;
            Header = item?.Name;
        }
    }
}

Item类并不特别。

public class Item
{
    public string Name { get; set; }
    public int Value { get; set; }

    public override string ToString() => Name;
}