2010-11-11 123 views
1

我是一個新的WPF用戶,我試圖圍繞模板包裹頭部。特別是我試圖模板一個TabControl。WPF TabControl模板

我對TabControl綁定到數據時實際產生的控件感到困惑。我需要的是每個選項卡在其內容部分都有一個單獨的控件副本。我發現的是,似乎創建了一組控件,並且當用戶從標籤頁到標籤頁單擊時,只是綁定的數據發生更改。

項目描述:

示例項目包括與一個TabControl的單一視圖的。在TabControl的內容模板中是一個ListBox。視圖被綁定到TabBindingViewModel類的對象。這個類有一個名爲Tabs的屬性,它是TabViewModel對象的ObservableCollection。 TabViewModel類有兩個屬性:TabHeader和Guid。 TabViewModel.TabHeader是一個字符串,它包含將出現在選項卡上的文本,而TabViewModel.Guids是一個字符串的ObservableCollection。

當綁定,每個TabViewModel的TabBindingViewModel.Tabs集合中應該產生在與突片是所述TabViewModel.TabHeader屬性的報頭中的TabControl對象標籤。每個選項卡的內容應該是在TabViewModel.Guids集合中填充了字符串集合的ListBox。

問題

這一切都似乎呈現/綁定就好,但如果改變列表框的狀態(例如滾動或選擇項目),然後改變標籤,看來該狀態進行轉移到您剛剛選擇的新選項卡上的列表框。這使得我假設只有ListBox的一個實例(而不是5個單獨的實例),並且當您更改選項卡時,數據是唯一發生更改的事物。

在另一個場景中,我沒有將集合綁定到模板,而是使用它自己的xaml中的ListBox顯式定義每個TabItem對象。這一次,當我從標籤點擊標籤時,每個ListBox保持它自己的狀態。

我的假設是否正確?如果是這樣,我怎樣才能在第二種情況下實現結果,同時仍然利用模板? (這是一個簡化的例子,我的真實世界內容要複雜得多)

在此先感謝您的幫助!

我的例子的源代碼如下。

視圖類

1. TabBinding

<Window x:Class="TabBindingQuestion.View.TabBinding" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:vm="clr-namespace:TabBindingQuestion.ViewModel" 
     Title="TabTemplateView" 
     Height="344" Width="618"> 
    <Window.Resources> 
     <vm:TabBindingViewModel x:Key="Data" /> 
    </Window.Resources> 
    <Grid DataContext="{StaticResource Data}"> 
     <TabControl Width="Auto" 
        Height="Auto" 
        ItemsSource="{Binding Tabs}" 
        IsSynchronizedWithCurrentItem="True"> 
      <TabControl.ItemContainerStyle> 
       <Style TargetType="TabItem"> 
        <Setter Property="Header" Value="{Binding TabHeader}" /> 
        <Setter Property="ContentTemplate"> 
         <Setter.Value> 
          <DataTemplate> 
           <ListBox Width="Auto" 
             Height="Auto" 
             ItemsSource="{Binding Guids}" /> 
          </DataTemplate> 
         </Setter.Value> 
        </Setter> 
       </Style> 
      </TabControl.ItemContainerStyle> 
     </TabControl> 
    </Grid> 
</Window> 

視圖模型類

2. ViewModelBase

using System.ComponentModel; 

namespace TabBindingQuestion.ViewModel 
{ 
    class ViewModelBase : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged(object sender, string propertyName) 
     { 
      if (this.PropertyChanged != null) 
      { 
       PropertyChanged(sender, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 
} 

3。TabBindingViewModel

using System.Collections.ObjectModel; 

namespace TabBindingQuestion.ViewModel 
{ 
    class TabBindingViewModel : ViewModelBase 
    { 
     #region Members 

     private ObservableCollection<TabViewModel> _Tabs; 
     public ObservableCollection<TabViewModel> Tabs 
     { 
      get { return _Tabs; } 
      set 
      { 
       _Tabs = value; 
       OnPropertyChanged(this, "Tabs"); 
      } 
     } 

     #endregion 

     #region Constructor 

     public TabBindingViewModel() 
     { 
      var tabs = new ObservableCollection<TabViewModel>(); 
      for (int i = 1; i <= 5; i++) 
      { 
       tabs.Add(new TabViewModel() { TabHeader = "Tab " + i.ToString() }); 
      } 
      Tabs = tabs; 
     } 

     #endregion 
    } 
} 

4. TabViewModel

using System; 
using System.Collections.ObjectModel; 

namespace TabBindingQuestion.ViewModel 
{ 
    class TabViewModel : ViewModelBase 
    { 
     #region Members 

     private string _TabHeader; 
     public string TabHeader 
     { 
      get { return _TabHeader; } 
      set 
      { 
       _TabHeader = value; 
       OnPropertyChanged(this, "TabHeader"); 
      } 
     } 

     private ObservableCollection<string> _Guids; 
     public ObservableCollection<string> Guids 
     { 
      get { return _Guids; } 
      set 
      { 
       _Guids = value; 
       OnPropertyChanged(this, "Guids"); 
      } 
     } 

     #endregion 

     #region Constructors 

     public TabViewModel() 
     { 
      var guids = new ObservableCollection<string>(); 
      for (int i = 1; i < 100; i++) 
      { 
       guids.Add(Guid.NewGuid().ToString()); 
      } 
      Guids = guids; 
     } 

     #endregion 
    } 
} 

回答

1

是在TabControl的重新使用的控制,如果他們切換標籤時是相同的。它還根據需要卸載/重新加載控件,導致未綁定的控件被重置。例如,如果Tab1有一個ListBox並且選擇了ItemA,並且選擇ItemB並將選項卡切換爲沒有列表框的選項卡,則當您返回到Tab1時,ItemA再次被選中。

最好的事情就是將你的UI屬性綁定到後面的代碼中。例如,您的TabControl可能包含一個TabItemViewModel的列表,並且每個ViewModel應該包含代表您的UI狀態的屬性,例如ListBox.SelectedItems或CheckBox.IsChecked。

+0

謝謝您的回覆。 雖然你提出的建議不是一個可行的解決方案。由於每個選項卡的內容在實際場景中要複雜得多,並且包含複雜的第三方控件。此外,潛在的大量數據綁定到第三方控件,並且當用戶導航到不同的選項卡時,我無法保證重新綁定數據。 – BigFunger 2010-11-11 19:40:48

+0

如果我明確地定義了5個標籤,每個標籤具有相同的內容(除了綁定到它們的數據),我就可以獲得我所追求的功能。但是,我希望功能根據我的收藏大小動態變化,而且我顯然不想複製該代碼。我發現很難相信沒有辦法使用模板來複制它。 – BigFunger 2010-11-11 19:46:03

+0

Hrrm你可以嘗試在這裏找到的代碼:http://www.pluralsight-training.net/community/blogs/eburke/archive/2009/04/30/keeping-the-wpf-tab-control-from-destroying- its-children.aspx我使用它來防止TabControl在視圖不存在時銷燬它的子項,並且可能會應用相同的原則來維護每個選項卡的狀態。我現在沒有時間對它進行測試,但你可能能夠弄清楚它的一些事情 – Rachel 2010-11-11 21:10:11