[英]How can I bind a button to a viewmodel command from within a data template that's in Page.Resources?
[英]Bind Button Command from within style template
我有一个选项卡式的部分,我试图连接用于动态关闭和打开新选项卡的命令。 问题是我无法理解如何从我的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样式模板中的视图模型中引用Icommand,或者,如果有更好的方法,可以得到相同的结果,将受到欢迎。
2)为什么当我运行该应用程序时,创建了一个空选项卡,但我的可观察的收藏列表却为空
编辑:RelayCommand在程序的另一部分工作正常,那不是问题,通过触发workin和所有方法都可以使tabItem呈现为正常,我仍然无法理解如何将我的ViewModel命令与Templated选项卡绑定制作。
编辑2:该命令现在正在工作,显然该命令在资源字典中无法识别,并标记为:“无法在类型对象的DataContext中解析属性'CloseWorkSpaceCommand'”,但将按钮的DataContext设置为:DataContext =“ {Binding RelativeSource = {RelativeSource FindAncestor,AncestorType = {x:Type TabControl}},Path = DataContext}”可以在运行应用程序时完成工作(Visual Studio仍然对DataContext类型表示歉意,这并不意味着什么)。 默认情况下仍然创建一个标签,为什么? 有没有一种方法可以纠正DataContext类型的代码异味?
似乎您想像我们在浏览器中看到的那样在每个选项卡上添加一个关闭按钮。 这样做似乎很复杂。 但是,让我尝试为您分解。
首先,让我们开始说明阻止我们这样做的障碍:
- TabItem没有命令属性,可以在其中绑定CloseWorkSpaceCommand。
- 该选项卡项没有关闭按钮。 这就是您创建模板的原因。 但是仍然不能将模板绑定到命令属性,因为TabItem没有这样的命令属性。
- 您如何将按钮的命令连接到视图模型的CloseWorkSpaceCommand属性?
现在,让我们尝试一个接一个地解决每个问题。
要解决此问题,我们需要为具有Command属性的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。
像您所做的一样,我们需要一个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>
要将viewmodel.CloseWorkSpaceCommand绑定到选项卡项目,我们可以在ItemContainerStyle的设置器中进行此操作。
<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}"
这是完整的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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.