2015-10-15 38 views
0

我有一個選項卡式部分,我試圖連接關閉和動態打開新選項卡的命令。問題是我不能理解如何綁定我的tabItem模板(它有一個按鈕)的命令。下面是代碼:從樣式模板中綁定按鈕命令

(含有標籤部分的,簡化的用戶控件..):

<UserControl.DataContext> 
    <vm:InicioViewModel /> 
</UserControl.DataContext> 
<UserControl.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="../Visual Resources/TabResource.xaml"/> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</UserControl.Resources>   

    <ContentPresenter HorizontalAlignment="Stretch" Grid.Column="1"> 
     <ContentPresenter.Content> 
      <TabControl Name="tc"> 
       <TabControl.DataContext> 
        <vm:WorkSpaceViewModel/> 
       </TabControl.DataContext> 
       <TabControl ItemsSource="{Binding Items}"/> 
      </TabControl> 

     </ContentPresenter.Content> 
    </ContentPresenter> 
</Grid> 

(這裏是爲TabItem的資源字典):

<Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type TabItem}"> 
       <Border x:Name="TaBorder" Width="auto" Height="auto" 
         BorderBrush="LightGray" 
         BorderThickness="0.5,0.5,0.5,0" 
         CornerRadius="3,3,0,0" 
         Background="WhiteSmoke"> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="*" /> 
          <ColumnDefinition Width="20" /> 
         </Grid.ColumnDefinitions> 
         <TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" /> 
         <Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11" 
           VerticalAlignment="Center" 
           HorizontalAlignment="Center" 
           Background="Transparent" 
           DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=DataContext}" 
           Command="{Binding CloseWorkSpaceCommand}" 
           (Donkt know what yo put in command to   reference my viewmodel Icommand) 
           BorderThickness="0" 
           > 
          <!-- ETC -->     

(Here my viewModel):

class InicioViewModel : ViewModelBase 
{ 
    private WorkSpaceViewModel _workSpaceVm; 

    public InicioViewModel() 
    { 

    } 

    public WorkSpaceViewModel WorkSpaceVm 
    { 
     get { return _workSpaceVm; } 
     set { _workSpaceVm = value; } 
    } 
} 

(WorkSpaceViewModel ..):

public class WorkSpaceViewModel 
{ 
    private ObservableCollection<IWorkSpaceItemVm> _items;   

    private RelayCommand _closeWorkSpaceCommand;   

    public WorkSpaceViewModel() 
    { 
     _items = new ObservableCollection<IWorkSpaceItemVm>(); 
    } 

    public ObservableCollection<IWorkSpaceItemVm> Items 
    { 
     get { return _items; } 
     set { _items = value; } 
    }  

    public ICommand CloseWorkSpaceCommand 
    { 
     get 
     { 
      return _closeWorkSpaceCommand ?? (_closeWorkSpaceCommand = new RelayCommand(
       param => CloseWorkSpace_Execute(param), 
       param => CloseWorkSpace_CanExecute(param) 
       )); 
     } 
    }  

    private void CloseWorkSpace_Execute(object parm) 
    { 
     MessageBox.Show("asdasdasd"); 
    } 

    private bool CloseWorkSpace_CanExecute(object parm) 
    { 
     return true; 
    } 
} 

正如你可以注意到我只有CloseWorkSpace_Execute顯示用於測試目的一個消息。

1)我如何從我的tabItem樣式模板中引用我的viewmodel中的Icommand,或者如果有更好的方法使用相同的結果將會受到歡迎。

2)爲什麼當我運行應用程序創建一個空的選項卡,我有我的觀察集合列表爲空

編輯: 的RelayCommand是工作在程序的其他部分確定,那不是問題, tabItem被渲染成可以觸發工作和所有,我仍然不能讓我的頭腦如何從我的viewmodel綁定命令與我製作的模板tabItem。

編輯2: 該命令現在正在工作,顯然該命令無法在資源字典中識別,並標記爲:「在對象類型的DataContext中不能識別屬性'CloseWorkSpaceCommand'」,但設置按鈕的DataContext爲: DataContext =「{Binding RelativeSource = {RelativeSource FindAncestor,AncestorType = {x:Type TabControl}},Path = DataContext}」 運行應用程序時完成工作(Visual Studio仍然道歉DataContext類型,不知道它是什麼手段)。 默認情況下還有一個選項卡,爲什麼? 是否有一種方法來糾正與DataContext類型的代碼氣味?

+0

乍一看,似乎你的困難可能與安置模板e放在單獨的資源字典中,使訪問任何你想綁定的東西變得不那麼方便。想到的一種可能的解決方案是在同一個XAML文件中聲明一個合適的'Command'並綁定到該文件,然後在別處建立一個綁定(例如'CommandBinding')來響應該命令。但是,這裏有太多的代碼可以肯定地知道模糊問題的哪一部分給你帶來麻煩,沒關係花費時間來解決問題。 –

+0

請編輯,以便只包含可靠地再現問題的[良好,_minimal_,_complete_代碼示例](https://stackoverflow.com/help/mcve)。 –

+0

嘿,彼得,我編輯它,我不明白你在說什麼,你說問題是資源字典聲明的參考?,那麼,相對資源是什麼?有另一種方法可以實現這一目標嗎?我想綁定一個命令到樣式模板中的按鈕,無論我是否必須在模板中聲明,內聯在我的用戶或我的tabcontrol資源中,但我不知道如何引用我在tabItem模板中創建的按鈕 –

回答

1

看起來你想在每個標籤上添加一個關閉按鈕,就像我們在瀏覽器中看到的那樣。這樣做似乎相當複雜。但讓我試着爲你分解它。

首先讓我們通過闡明,阻止我們這樣做的路障開始:

  1. 的TabItem的沒有,你可以綁定你CloseWorkSpaceCommand命令屬性。
  2. 該標籤項沒有關閉按鈕。這就是您創建模板的原因。但是,由於TabItem沒有這樣的命令屬性,所以仍然無法將模板綁定到命令屬性。
  3. 您將如何將按鈕的命令連接到視圖模型的CloseWorkSpaceCommand屬性?

現在讓我們來嘗試解決每一個問題一個接一個。

  1. 要解決這個問題,我們需要創建一個具有命令屬性的TabItem的自定義控件。

    public class ClosableTabItem : TabItem 
    { 
        public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(ClosableTabItem), new PropertyMetadata(null));   
        public ICommand CloseCommand 
        { 
         get { return (ICommand)GetValue(CloseCommandProperty); } 
         set { SetValue(CloseCommandProperty, value); } 
        } 
    } 
    

    因爲我們有一個自定義選項卡的項目,我們還需要一個自定義的TabControl的,因爲我們需要在此改變GetContainerForItemOverride()方法。

    public class ClosableTabControl : TabControl { protected override DependencyObject GetContainerForItemOverride() { return new ClosableTabItem(); } }

    這解決問題#1。

  2. 就像你所做的一樣,我們需要有一個ControlTemplate,所以我們可以在每個標籤上放置一個關閉按鈕。

    <ControlTemplate TargetType="{x:Type local:ClosableTabItem}"> <Border x:Name="TaBorder" Width="auto" Height="auto" Background="LightGray" CornerRadius="4,4,0,0" Margin="0,2,3,0"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="20" /> </Grid.ColumnDefinitions> <TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" /> <Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{TemplateBinding CloseCommand}" BorderThickness="0" Content="X" Background="Red" FontSize="8"> </Button> </Grid> </Border> </ControlTemplate>

  3. 到viewmodel.CloseWorkSpaceCommand綁定到我們在ItemContainerStyle的setter做到這一點的標籤項目。

    <local:ClosableTabControl.ItemContainerStyle> <Style TargetType="local:ClosableTabItem" BasedOn="{StaticResource {x:Type TabItem}}"> <Setter Property="CloseCommand" Value="{Binding DataContext.CloseWorkSpaceCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> ...

    你會注意到,我使用的是相對源窗口的DataContext。

    現在要將ClosableTabItem的CloseCommand屬性綁定到模板內Button的Command屬性,我們現在在控件模板的按鈕內部進行模板綁定。

    您也可以在答案#2代碼示例中看到此內容。

    Command="{TemplateBinding CloseCommand}"

下面是完整的XAML代碼:

<Window x:Class="WpfApplication1.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:WpfApplication1" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> <Grid> <local:ClosableTabControl ItemsSource="{Binding Items}"> <local:ClosableTabControl.ItemContainerStyle> <Style TargetType="local:ClosableTabItem" BasedOn="{StaticResource {x:Type TabItem}}"> <Setter Property="CloseCommand" Value="{Binding DataContext.CloseWorkSpaceCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ClosableTabItem}"> <Border x:Name="TaBorder" Width="auto" Height="auto" Background="LightGray" CornerRadius="4,4,0,0" Margin="0,2,3,0"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="20" /> </Grid.ColumnDefinitions> <TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" /> <Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{TemplateBinding CloseCommand}" BorderThickness="0" Content="X" Background="Red" FontSize="8"> </Button> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </local:ClosableTabControl.ItemContainerStyle> <TabControl.Items> </TabControl.Items> </local:ClosableTabControl> </Grid> </Window>

enter image description here

+0

嘿謝謝,我在想我必須註冊tabItem作爲新的控制,很好的建議,並很好地解釋。順便說一句,我現在要嘗試一下,我應該如何處理mi字典中的選項卡項目的樣式資源?我可以使用它嗎?我可以在同一個字典中的mainWindow中聲明直接聲明的控件模板嗎?最後一個,如果你不介意的話:我應該通過什麼命令參數來請求關閉命令?再次感謝! –

+0

是的,您仍然可以使用您在字典中創建的樣式,我只是將樣式放在xaml中,以使代碼更具可讀性,因此您不必從字典中查找樣式。對於命令參數,它是可選的。我認爲你的命令參數也是正確的。我會更新代碼。 – Lance