2017-11-11 126 views
0

我认为我在寻找的是MVVM,但我看过的示例并没有帮助,因此基于我的问题的示例应该可以提供帮助。我已经有了TabControl中的内容,所以我一直无法使用TabControl.ItemsSource = CourtCases,因为它会引发异常;TabControl将ItemsSource绑定到带有现有TabItem的列表

Items collection must be empty before using ItemsSource. 

...和使用​​可能需要更多的工作,因为一些标签将不得不关闭。

我有一个TabControl,其中第一个选项卡包含一个DataGrid与人员列表,我希望每当在DataGrid中单击一个项目时,会创建一个包含该人员详细信息的新选项卡。我想将人物对象传递给TabItem“范围/类”,并显示该人的内容。我为人物详细信息TabItem创建了一个DataTemplate,您可以在下面看到它;

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

查看主 - 细节绑定。这是一个[SAMPLE](https://code.msdn.microsoft.com/windowsdesktop/CSWPFMasterDetailBinding-c78566ae)。 – jsanalytics

+0

你正试图以一种他们真正没有设计的方式来使用控件。在这种情况下,您应该将控件包装在UserControl中,然后公开您自己的ItemsSource DP,并在代码隐藏中手动管理选项卡。 – Will

+0

是的,这就是我所做的。我意识到这是不可能的。 – LogicDev

回答

0

这不是不可能的,除非我错过了关于您的请求的内容。我会说它听起来不像一个好的UX,但你比我更了解你的用户和你的用例。

我放在一起,我认为会做你想做的事情。你需要适应你的数据。我希望它有助于不管。请记住,这仅仅是概念代码的证明。

首先是MainWindow的XAML。这里没什么特别的。它开始作为一个简单的TabControl托管TabItemListbox

<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; 
} 
相关问题