2015-10-15 43 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