![](/img/trans.png)
[英]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.