[英]How to track WPF commands?
在WPF應用程序中,我希望有一個用戶跟蹤系統來統計用戶使用該應用程序的方式。 換句話說,我正在尋找一種方法來跟蹤正在執行的命令以及用戶如何觸發它們(通過單擊工具欄按鈕,使用鍵盤快捷鍵等)。 到目前為止,我還沒有找到一個很好的方法來使用WPF命令模式...
您是否有關於如何在不覆蓋應用程序中使用的每個控件的情況下實現/設計此類內容的想法/建議?
為了便於討論,我創建了一個非常基本的WPF應用程序,其中包含一個帶有單個Save按鈕,TextBox和ListBox的工具欄。 我還添加了一個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層中實現嗎? 當我們到達命令處理程序時,已經太晚了:我們丟失了這些信息。 我們真正了解所使用設備的唯一地方是View本身。 如何將此信息傳遞給Command處理程序? 唯一的方法是覆蓋Button控件來攔截Click和KeyDown事件,以便為命令處理程序提供額外的上下文?
如果使用MVVM模式,那么Command將從視圖綁定到View模型中的Command實例。 您可以使用創建ICommand實現,該實現在執行事件時提供有關其自身的一些詳細信息。 也許使用命令提供程序/工廠/無論創建每個命令並將其連接到記錄器/跟蹤器。
創建具有Stack<ICommand>
屬性的Singleton或static
類,並將對此類的引用傳遞給Window
(或最好是視圖模型)。 您當然應該使用一些典型的AddCommand
和RemoveCommand
方法封裝Stack
對象。 然后,每當調用ICommand
,將其Push
入Stack
。
但是,您需要在單獨的類中定義ICommand
,或者最好使用在線查找的RelayCommand
形式。 這是一個例子:
private ActionCommand deleteCommand = new ActionCommand(action => DeleteCommand(AudioTrack),
canExecute => CanDelete(AudioTrack));
public override ICommand Delete
{
get { return deleteCommand; }
}
private void DeleteCommand(AudioTrack audioTrack)
{
// Do work then add to Stack in CommandManager
CommandManager.AddCommand(deleteCommand);
}
private bool CanDelete(AudioTrack audioTrack)
{
return audioTrack != null;
}
我不確定你的第二個問題意味着什么,因為ICommand
被設置為相關控件的Command
屬性的值,所以你應該已經知道它們是什么控件,例如:
<MenuItem Header="Delete track" Command="{Binding Delete}"
CommandParameter="{Binding Release.ThinDiscs.CurrentItem}">
<MenuItem.Icon>
<Image Source="pack://application:,,,/App;component/Images/Delete.png" />
</MenuItem.Icon>
</MenuItem>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.