2017-11-11 4 views
0

私が探しているのはMVVMだと思っていますが、私が見てきた例は私の問題に基づいた例を助けてくれません。私は既にTabControlのコンテンツを持っているので、例外がスローされるのでTabControl.ItemsSource = CourtCasesを使用することができませんでした。TabControl ItemsSourceを既存のTabItemでリストにバインドする

Items collection must be empty before using ItemsSource. 

...といくつかのタブが閉じられなければならないので、​​を使用すると、より多くの作業が必要になることがあります。

私はTabControlを持っています。最初のタブには人のリストを含むDataGridがあり、DataGridでアイテムがクリックされるたびにその人の詳細を含む新しいタブが作成されます。 PersonオブジェクトをTabItemの "scope/class"に渡して、その人の内容を表示する必要があります。私はあなたが下に見ることができる人の詳細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です。ここには何も特別なものはありません。それはTabItemListboxをホストする単純なTabControlとして始まります。

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

コードの背後には、興味深いものがほとんど発生します。アイテムのタブが既に存在するかどうかに基づいて、イベントハンドラで2つのうちの1つを実行します。つまり、タブを作成するか、タブを選択します。

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; 
} 
関連する問題