2017-11-11 127 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; 
} 
相關問題