如何从 DataTemplate 引发命令并使用命令参数?
How to raise a command from a DataTemplate and using command parameter?
我有多个 DataTemplates,里面有一个 TextBox,它们是用 DataTemplateSelector 选择的。 TextBoxes 表示树中的节点。当我在运行时单击 TextBox 时,应该触发 ZoomPlusButtonCommand 命令。这样可行。但我想知道,我的 ObservableCollection 中的哪个 TextBox 触发了这个命令。每个节点都有一个 id,所以我希望这个 id 作为命令参数。我该怎么做?
XAML:
<DataTemplate x:Key="RootNode" DataType="{x:Type vm:TreeNodeViewModel}">
<TextBox Tag="{Binding NodeTag}" Text="{Binding Node.Description}" Margin="{Binding NodeMargin}">
<TextBox.Style>
<Style>
<Setter Property="TextBox.Background" Value="#FFF6212D"/>
...
<Style.Triggers>
<Trigger Property="TextBox.IsMouseOver" Value="True">
<Setter Property="TextBox.BorderBrush" Value="AliceBlue"/>
</Trigger>
...
</Style.Triggers>
</Style>
</TextBox.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.ZoomPlusButtonCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
MainViewModel:
public class MainViewModel : ViewModelBase
{
// list of all existing nodes in the tree editor
public ObservableCollection<TreeNodeViewModel> Nodes { get; set; }
// commands
private ZoomPlusButtonCommand _zoomPlusButtonCommand;
public ZoomPlusButtonCommand ZoomPlusButtonCommand
{
get
{
return _zoomPlusButtonCommand;
}
set
{
_zoomPlusButtonCommand = value;
}
}
public MainViewModel()
{
Nodes = new ObservableCollection<TreeNodeViewModel>();
Nodes.Add(new TreeNodeViewModel(4,0,"TEST1",new Thickness(0, 100, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 1, "TEST2", new Thickness(100, 150, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 2, "TEST3", new Thickness(200, 200, 0, 0)));
// initialize commands
_zoomPlusButtonCommand = new ZoomPlusButtonCommand(this);
}
}
文本框(节点)的ViewModel:
public class TreeNodeViewModel : ViewModelBase
{
private TreeNode _node;
public TreeNode Node
{
get
{
return _node;
}
set
{
_node = value;
RaisePropertyChanged(nameof(Node));
}
}
private string _nodeTag;
public string NodeTag
{
get
{
return _nodeTag;
}
set
{
_nodeTag = value;
RaisePropertyChanged(nameof(NodeTag));
}
}
private Thickness _nodeMargin;
public Thickness NodeMargin
{
get
{
return _nodeMargin;
}
set
{
_nodeMargin = value;
RaisePropertyChanged(nameof(NodeMargin));
}
}
public TreeNodeViewModel(int id, int level, string tag, Thickness margin)
{
Node = new TreeNode();
Node.Id = id;
Node.Level = level;
Node.Description = "Knoten";
NodeTag = tag;
NodeMargin = margin;
}
}
命令:
public class ZoomPlusButtonCommand : ICommand
{
private MainViewModel mainViewModel;
public ZoomPlusButtonCommand(MainViewModel vm)
{
mainViewModel = vm;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (mainViewModel.ComboBoxZoomSelectedIndex - 1 >= 0)
{
mainViewModel.ComboBoxZoomSelectedIndex -= 1;
}
}
public event EventHandler CanExecuteChanged
{
// only implemented to suppress the compiler warning that this event will never be used
add { }
remove { }
}
}
假设您的 ICommand
实现(ZoomPlusButtonCommand
class)可以处理命令参数,您可以像这样更改代码:
XAML
<DataTemplate x:Key="RootNode" DataType="{x:Type vm:TreeNodeViewModel}">
<TextBox Tag="{Binding NodeTag}" Text="{Binding Node.Description}" Margin="{Binding NodeMargin}">
<TextBox.Style>
<Style>
<Setter Property="TextBox.Background" Value="#FFF6212D"/>
...
<Style.Triggers>
<Trigger Property="TextBox.IsMouseOver" Value="True">
<Setter Property="TextBox.BorderBrush" Value="AliceBlue"/>
</Trigger>
...
</Style.Triggers>
</Style>
</TextBox.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.ZoomPlusButtonCommand}" CommandParameter="{Binding NodeTag}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
MainViewModel
public class MainViewModel : ViewModelBase
{
// list of all existing nodes in the tree editor
public ObservableCollection<TreeNodeViewModel> Nodes { get; set; }
// commands
private ZoomPlusButtonCommand<string> _zoomPlusButtonCommand;
public ZoomPlusButtonCommand<string> ZoomPlusButtonCommand
{
get
{
return _zoomPlusButtonCommand;
}
set
{
_zoomPlusButtonCommand = value;
}
}
public MainViewModel()
{
Nodes = new ObservableCollection<TreeNodeViewModel>();
Nodes.Add(new TreeNodeViewModel(4,0,"TEST1",new Thickness(0, 100, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 1, "TEST2", new Thickness(100, 150, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 2, "TEST3", new Thickness(200, 200, 0, 0)));
// initialize commands
_zoomPlusButtonCommand = new ZoomPlusButtonCommand<string>(this);
}
}
我有多个 DataTemplates,里面有一个 TextBox,它们是用 DataTemplateSelector 选择的。 TextBoxes 表示树中的节点。当我在运行时单击 TextBox 时,应该触发 ZoomPlusButtonCommand 命令。这样可行。但我想知道,我的 ObservableCollection 中的哪个 TextBox 触发了这个命令。每个节点都有一个 id,所以我希望这个 id 作为命令参数。我该怎么做?
XAML:
<DataTemplate x:Key="RootNode" DataType="{x:Type vm:TreeNodeViewModel}">
<TextBox Tag="{Binding NodeTag}" Text="{Binding Node.Description}" Margin="{Binding NodeMargin}">
<TextBox.Style>
<Style>
<Setter Property="TextBox.Background" Value="#FFF6212D"/>
...
<Style.Triggers>
<Trigger Property="TextBox.IsMouseOver" Value="True">
<Setter Property="TextBox.BorderBrush" Value="AliceBlue"/>
</Trigger>
...
</Style.Triggers>
</Style>
</TextBox.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.ZoomPlusButtonCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
MainViewModel:
public class MainViewModel : ViewModelBase
{
// list of all existing nodes in the tree editor
public ObservableCollection<TreeNodeViewModel> Nodes { get; set; }
// commands
private ZoomPlusButtonCommand _zoomPlusButtonCommand;
public ZoomPlusButtonCommand ZoomPlusButtonCommand
{
get
{
return _zoomPlusButtonCommand;
}
set
{
_zoomPlusButtonCommand = value;
}
}
public MainViewModel()
{
Nodes = new ObservableCollection<TreeNodeViewModel>();
Nodes.Add(new TreeNodeViewModel(4,0,"TEST1",new Thickness(0, 100, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 1, "TEST2", new Thickness(100, 150, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 2, "TEST3", new Thickness(200, 200, 0, 0)));
// initialize commands
_zoomPlusButtonCommand = new ZoomPlusButtonCommand(this);
}
}
文本框(节点)的ViewModel:
public class TreeNodeViewModel : ViewModelBase
{
private TreeNode _node;
public TreeNode Node
{
get
{
return _node;
}
set
{
_node = value;
RaisePropertyChanged(nameof(Node));
}
}
private string _nodeTag;
public string NodeTag
{
get
{
return _nodeTag;
}
set
{
_nodeTag = value;
RaisePropertyChanged(nameof(NodeTag));
}
}
private Thickness _nodeMargin;
public Thickness NodeMargin
{
get
{
return _nodeMargin;
}
set
{
_nodeMargin = value;
RaisePropertyChanged(nameof(NodeMargin));
}
}
public TreeNodeViewModel(int id, int level, string tag, Thickness margin)
{
Node = new TreeNode();
Node.Id = id;
Node.Level = level;
Node.Description = "Knoten";
NodeTag = tag;
NodeMargin = margin;
}
}
命令:
public class ZoomPlusButtonCommand : ICommand
{
private MainViewModel mainViewModel;
public ZoomPlusButtonCommand(MainViewModel vm)
{
mainViewModel = vm;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (mainViewModel.ComboBoxZoomSelectedIndex - 1 >= 0)
{
mainViewModel.ComboBoxZoomSelectedIndex -= 1;
}
}
public event EventHandler CanExecuteChanged
{
// only implemented to suppress the compiler warning that this event will never be used
add { }
remove { }
}
}
假设您的 ICommand
实现(ZoomPlusButtonCommand
class)可以处理命令参数,您可以像这样更改代码:
XAML
<DataTemplate x:Key="RootNode" DataType="{x:Type vm:TreeNodeViewModel}">
<TextBox Tag="{Binding NodeTag}" Text="{Binding Node.Description}" Margin="{Binding NodeMargin}">
<TextBox.Style>
<Style>
<Setter Property="TextBox.Background" Value="#FFF6212D"/>
...
<Style.Triggers>
<Trigger Property="TextBox.IsMouseOver" Value="True">
<Setter Property="TextBox.BorderBrush" Value="AliceBlue"/>
</Trigger>
...
</Style.Triggers>
</Style>
</TextBox.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.ZoomPlusButtonCommand}" CommandParameter="{Binding NodeTag}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</DataTemplate>
MainViewModel
public class MainViewModel : ViewModelBase
{
// list of all existing nodes in the tree editor
public ObservableCollection<TreeNodeViewModel> Nodes { get; set; }
// commands
private ZoomPlusButtonCommand<string> _zoomPlusButtonCommand;
public ZoomPlusButtonCommand<string> ZoomPlusButtonCommand
{
get
{
return _zoomPlusButtonCommand;
}
set
{
_zoomPlusButtonCommand = value;
}
}
public MainViewModel()
{
Nodes = new ObservableCollection<TreeNodeViewModel>();
Nodes.Add(new TreeNodeViewModel(4,0,"TEST1",new Thickness(0, 100, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 1, "TEST2", new Thickness(100, 150, 0, 0)));
Nodes.Add(new TreeNodeViewModel(56, 2, "TEST3", new Thickness(200, 200, 0, 0)));
// initialize commands
_zoomPlusButtonCommand = new ZoomPlusButtonCommand<string>(this);
}
}