【发布时间】:2015-06-04 13:22:51
【问题描述】:
在 WPF 应用程序中,我希望有一个用户跟踪系统来记录用户使用应用程序的方式。换句话说,我正在寻找一种方法来跟踪正在执行的命令以及用户如何触发它们(通过单击工具栏按钮、使用键盘快捷键等)。到目前为止,在使用 WPF 命令模式时,我还没有找到一个很好的方法来做到这一点......
您对如何在不覆盖应用程序中使用的每个控件的情况下实现/设计类似的东西有想法/建议?
出于讨论的目的,我创建了一个非常基本的 WPF 应用程序,其中包含一个带有单个保存按钮、一个文本框和一个列表框的工具栏。我还添加了一个 KeyBinding 以在按下 CTRL+S 时触发 Save 命令。
第一个挑战是确定使用哪个设备(鼠标或键盘)触发命令。
第二个挑战是确定用于触发命令的控件是什么(命令源)。我不想知道触发命令时哪个控件具有键盘焦点,我想知道用于触发命令的控件(通常是按钮、超链接、来自 ContextMenu 的 MenuItem 等)
MainWindow.xaml
<Window x:Class="TrackingCommands.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" x:Name="Me" Height="480" Width="600">
<Window.CommandBindings>
<CommandBinding Command="Save" Executed="OnSaveCommandExecuted" CanExecute="OnSaveCommandCanExecute" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Save" Gesture="CTRL+S"/>
</Window.InputBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToolBarTray Grid.Row="0">
<ToolBar>
<Button Command="Save" Content="Save"/>
</ToolBar>
</ToolBarTray>
<TextBox Grid.Row="1" TextWrapping="Wrap" AcceptsReturn="True"/>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void OnSaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
private void OnSaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
}
编辑
我意识到我最初的问题有点含糊,我很抱歉。我会尽量提供更多信息并提出更准确的问题。
我知道存储已执行的命令列表很简单。这里的挑战是检索最初用于触发命令的设备:鼠标还是键盘?
通过将跟踪逻辑放在“已执行”处理程序中,此时无法确定用户是通过鼠标单击按钮、在按钮上按 Enter 还是使用键盘触发了命令捷径。在我的示例中,可以通过单击工具栏按钮或按键盘上的 CTRL+S 来触发相同的命令。如何跟踪这些将触发相同命令的单独操作?
这可以在 ViewModel 层实现吗?当我们到达命令处理程序时,已经太晚了:我们已经丢失了这些信息。我们真正知道使用的设备的唯一地方是视图本身。如何将此信息传递给命令处理程序?这样做的唯一方法是重写 Button 控件以拦截 Click 和 KeyDown 事件,以便为命令处理程序提供额外的上下文?
【问题讨论】:
-
构建一个类来保存你想要的所有数据。
-
这个主题比你想象的要复杂一些......但是像PostSharp 这样的 AOP 方法让它变得容易多了,你应该能够用免费的方式完成你想要的版本(使用方法拦截)。