在样式模板

时间:2015-10-15 15:32:01

标签: c# wpf xaml

我有一个标签部分,我正在尝试连接关闭和动态打开新标签的命令。问题是我无法理解如何从我的tabItem模板(有一个按钮)中绑定命令。这是代码:

(包含标签部分的UserControl,简化..):

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

(这里是我的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中显示一个MessageBox用于测试目的。

1)如何从我的tabItem样式模板中引用我的viewmodel中的Icommand,或者,如果有更好的方法,欢迎使用相同的结果。

2)为什么当我运行应用程序时会创建一个空选项卡,我的可观察收集列表为空

编辑: RelayCommand在程序的另一部分工作正常,这不是问题,tabItem通过触发器workin和所有来呈现OK,我仍然无法理解如何将我的viewmodel中的命令与我制作的Templated tabItem绑定。

编辑2: 该命令现在正在运行,显然命令在资源字典中未被识别,并被标记为:&#34;无法解析属性&#39; CloseWorkSpaceCommand&#39;在类型为object&#34;的DataContext中,但将按钮的DataContext设置为: DataContext =&#34; {Binding RelativeSource = {RelativeSource FindAncestor,AncestorType = {x:Type TabControl}},Path = DataContext}&#34; 在运行应用程序时完成工作(visual studio仍在为DataContext类型道歉,不知道这意味着什么)。 默认情况下仍然会创建一个选项卡,为什么? 有没有办法用DataContext类型来纠正代码味道?

1 个答案:

答案 0 :(得分:1)

您似乎想在每个标签上添加一个关闭按钮,就像我们在浏览器中看到的一样。这样做似乎相当复杂。但是,让我试着为你分解它。

首先让我们先说明妨碍我们这样做的障碍:

  
      
  1. TabItem没有可以绑定CloseWorkSpaceCommand的命令属性。
  2.   
  3. 标签项没有关闭按钮。这就是你创建模板的原因。但是仍然无法对命令属性进行模板绑定,因为TabItem没有这样的命令属性。
  4.   
  5. 您如何将按钮的命令连接到viewmodel的CloseWorkSpaceCommand属性?
  6.   

现在让我们逐个解决每个问题。

  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绑定到Tab项,我们在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}}}" /> ...

    您会注意到我使用相对源来访问Window的DataContext。

    现在将ClosableTabItem的CloseCommand属性绑定到模板内Button的Command属性,现在我们在控件模板的按钮内进行模板绑定。

      

    您还可以在答案#2代码示例中看到这一点。

    Command="{TemplateBinding CloseCommand}"

  4. 以下是完整的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