2016-02-27 37 views
0

我想創建TabItem標頭與使用戶關閉標籤的按鈕。該對象的視覺表示和數據綁定就好了。TabControl與可關閉TabItem標頭

我已經試驗了DataContext,但到目前爲止我還沒有找到一個可行的解決方案。

我的XAML:

<TabControl  
        Grid.Column="3" 
        Grid.Row="2" 
        x:Name="TabControlTargets" 
        ItemsSource="{Binding Path=ViewModelTarget.IpcConfig.DatabasesList, UpdateSourceTrigger=PropertyChanged}" 
        SelectedItem="{Binding Path=ViewModelTarget.SelectedTab, UpdateSourceTrigger=PropertyChanged}"> 
         <TabControl.ItemTemplate> 
          <DataTemplate> 
           <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> 
            <TextBlock FontFamily="Calibri" FontSize="15" FontWeight="Bold" Foreground="{Binding FontColor}" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Margin="0,0,20,0"/> 
            <Button HorizontalAlignment="Left" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext}" Command="{Binding Path = ViewModelTarget.buttonRemoveDatabaseCommand}" 
              CommandParameter="**?**" 
             > 
             <Button.Content> 
              <Image Height="15" Width="15" Source="pack://application:,,,/Images/cancel.png" /> 
             </Button.Content> 
            </Button> 
           </StackPanel> 
          </DataTemplate> 

我有麻煩搞清楚如何設置我的按鈕的CommandParameter,以便它指的是正確的對象。

這裏是我的RelayCommand:

public ICommand buttonRemoveDatabaseCommand 
    { 
     get 
     { 
      if (_buttonRemoveDatabaseCommand == null) 
      { 
       _buttonRemoveDatabaseCommand = new RelayCommand(
        param => RemoveDatabase(param) 
        ); 
      } 
      return _buttonRemoveDatabaseCommand; 
     } 
    } 

這裏是我的RemoveDatabase功能:

public void RemoveDatabase(object dB) 
    { 
     this.IpcConfig.RemoveDataBase((PCDatabase)dB); 
    } 

我強烈希望的是堅持我的做法 「背後沒有代碼」 的解決方案。

+0

你能展示你的viewmodel – Flaugzig

+0

那麼'SelectedItem'呢?它有什麼問題? –

+0

@Eugene Podksal使用SelectedItem是我的第一個方法。但是,這將始終關閉所選的選項卡(即活動選項卡),該選項卡不一定是應該關閉的選項卡。 – Fang

回答

1

正如評論中指出的那樣,您可以使用CommandParameter="{Binding}"TabItem上下文傳遞給該命令。

雖然將命令移動到您的TabItem的ViewModel,但更好的方法是。

這裏是一個使用Prism和Prism的EventAggregator的示例實現。你當然可以在其他MVVM框架中實現它,甚至可以自己實現它,但這取決於你。

這將是您的TabControl ViewModel,其中包含所有數據庫的列表或任何其代表的意思。

public class DatabasesViewModel : BindableBase 
{ 
    private readonly IEventAggregator eventAggregator; 

    public ObservableCollection<DatabaseViewModel> Databases { get; private set; } 
    public CompositeCommand CloseAllCommand { get; } 

    public DatabasesViewModel(IEventAggregator eventAggregator) 
    { 
     if (eventAggregator == null) 
      throw new ArgumentNullException(nameof(eventAggregator)); 

     this.eventAggregator = eventAggregator; 

     // Composite Command to close all tabs at once 
     CloseAllCommand = new CompositeCommand(); 
     Databases = new ObservableCollection<DatabaseViewModel>(); 

     // Add a sample object to the collection 
     AddDatabase(new PcDatabase()); 

     // Register to the CloseDatabaseEvent, which will be fired from the child ViewModels on close 
     this.eventAggregator 
      .GetEvent<CloseDatabaseEvent>() 
      .Subscribe(OnDatabaseClose); 
    } 

    private void AddDatabase(PcDatabase db) 
    { 
     // In reallity use the factory pattern to resolve the depencency of the ViewModel and assing the 
     // database to it 
     var viewModel = new DatabaseViewModel(eventAggregator) 
     { 
      Database = db 
     }; 

     // Register to the close command of all TabItem ViewModels, so we can close then all with a single command 
     CloseAllCommand.RegisterCommand(viewModel.CloseCommand); 

     Databases.Add(viewModel); 
    } 

    // Called when the event is received 
    private void OnDatabaseClose(DatabaseViewModel databaseViewModel) 
    { 
     Databases.Remove(databaseViewModel); 
    } 
} 

每個標籤會得到一個DatabaseViewModel作爲上下文。這是關閉命令的定義。

public class DatabaseViewModel : BindableBase 
{ 
    private readonly IEventAggregator eventAggregator; 

    public DatabaseViewModel(IEventAggregator eventAggregator) 
    { 
     if (eventAggregator == null) 
      throw new ArgumentNullException(nameof(eventAggregator)); 

     this.eventAggregator = eventAggregator; 
     CloseCommand = new DelegateCommand(Close); 
    } 

    public PcDatabase Database { get; set; } 

    public ICommand CloseCommand { get; } 
    private void Close() 
    { 
     // Send a refence to ourself 
     eventAggregator 
      .GetEvent<CloseDatabaseEvent>() 
      .Publish(this); 
    } 
} 

當你點擊TabItem關閉按鈕,然後CloseCommand將被稱爲和發送一個事件,將通知所有用戶,這個標籤應該被關閉。在上面的示例中,DatabasesViewModel收聽此事件並將收到它,然後可以從ObservableCollection<DatabaseViewModel>集合中刪除它。

爲了使這種方式的優勢更加明顯,我添加了一個CloseAllCommand,這是一個CompositeCommand因爲它添加到Databases觀察到的集合,這將調用所有註冊的命令,調用時註冊到每個DatabaseViewModel小號CloseCommand

CloseDatabaseEvent是一個非常簡單的,只是一個標記,確定有效載荷它接收,這是在這種情況下DatabaseViewModel的類型。

public class CloseDatabaseEvent : PubSubEvent<DatabaseViewModel> { } 

在實際應用中要避免使用視圖模型(在這裏DatabaseViewModel)作爲有效載荷,因爲這導致緊密耦合,該事件聚合模式是爲了避免。

在這種情況下,它可以被認爲是可以接受的,因爲DatabasesViewModel需要知道DatabaseViewModel,但如果可能的話最好使用ID(Guid,int,string)。

這樣做的好處是,您還可以通過其他方式(即菜單,功能區或上下文菜單)關閉您的選項卡,其中您可能沒有對DatabasesViewModel數據上下文的引用。

+0

這肯定使我走上了正軌。萬分感謝。 – Fang