标签: routed-commands

WPF路由命令是解决问题还是使问题恶化?

据我所知,Command模式的目标是帮助将UI交互与应用程序逻辑分开.使用正确实现的命令,单击"打印"菜单项可能会产生一系列交互,如下所示:

(button) ---click executes command----> (command) ---calls Print() in app logic ---> (logic)
Run Code Online (Sandbox Code Playgroud)

这鼓励您将UI与应用程序逻辑分开.

我一直在研究WPF命令,在大多数情况下,我看到他们是如何实现这种模式的.但是,我觉得在某种程度上它们使命令模式变得复杂,并设法以不鼓励将UI与应用程序逻辑分离的方式实现它.

例如,考虑这个简单的WPF窗口,它有一个按钮将文本粘贴到文本框中:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Paste"
                        Executed="CommandBinding_Executed"/>
    </Window.CommandBindings>
    <StackPanel>
        <TextBox x:Name="txtData" />
        <Button Command="Paste" Content="Paste" />
    </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

这是代码隐藏:

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ApplicationCommands.Paste.Execute(null, txtData);
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

我从命令中获得了什么?在我看来,我可以轻松地将命令绑定事件处理程序中的代码放入按钮的Click事件中.当然,现在我可以将多个UI元素与粘贴命令相关联,我只需要使用一个事件处理程序,但是如果我想粘贴到几个不同的文本框呢?我必须使事件处理程序逻辑更复杂或编写更多的事件处理程序.所以现在,我觉得我有这个:

(button) ---executes Routed Command---> (Window) ---executes command …
Run Code Online (Sandbox Code Playgroud)

.net wpf routed-commands

5
推荐指数
1
解决办法
2861
查看次数

RoutedUICommand PreviewExecuted Bug?

我正在使用MVVM设计模式构建应用程序,我想使用ApplicationCommands类中定义的RoutedUICommands.由于View的CommandBindings属性(读取UserControl)不是DependencyProperty,因此我们无法将ViewModel中定义的CommandBindings直接绑定到View.我通过定义一个抽象的View类来解决这个问题,该类基于ViewModel接口以编程方式绑定它,该接口确保每个ViewModel都有一个ObBableCollection的CommandBindings.这一切都很好,但是,在某些情况下我想执行在不同类(View和ViewModel)相同命令中定义的逻辑.例如,保存文档时.

在ViewModel中,代码将文档保存到磁盘:

private void InitializeCommands()
{
    CommandBindings = new CommandBindingCollection();
    ExecutedRoutedEventHandler executeSave = (sender, e) =>
    {
        document.Save(path);
        IsModified = false;
    };
    CanExecuteRoutedEventHandler canSave = (sender, e) => 
    {
        e.CanExecute = IsModified;
    };
    CommandBinding save = new CommandBinding(ApplicationCommands.Save, executeSave, canSave);
    CommandBindings.Add(save);
}
Run Code Online (Sandbox Code Playgroud)

乍一看,前面的代码就是我想要做的,但是文档绑定到的View中的TextBox只在它失去焦点时才更新它的Source.但是,我可以通过按Ctrl + S保存文档而不会失去焦点.这意味着文档在源中更新的更改之前保存,实际上忽略了更改.但是,由于出于性能原因将UpdateSourceTrigger更改为PropertyChanged不是一个可行的选项,因此在保存之前必须强制更新其他内容.所以我想,让我们使用PreviewExecuted事件强制更新PreviewExecuted事件,如下所示:

//Find the Save command and extend behavior if it is present
foreach (CommandBinding cb in CommandBindings)
{
    if (cb.Command.Equals(ApplicationCommands.Save))
    {
        cb.PreviewExecuted += (sender, e) =>
        {
            if (IsModified)
            {
                BindingExpression be = rtb.GetBindingExpression(TextBox.TextProperty);
                be.UpdateSource();
            } …
Run Code Online (Sandbox Code Playgroud)

c# wpf routed-commands

5
推荐指数
1
解决办法
1315
查看次数

MVVM中的RoutedUICommand

我在应用程序中遇到了MVVM.我有一个TabControl,其每个Tab都有一个控件,允许以某种方式编辑文件.例如,文本文件或图像.每个控件都绑定到ViewModel区域中的一个类(如图所示).我也有RoutedUICommands.其中一个命令是WordWrap,只有在文本文件的情况下才有意义.此命令在MenuItem或Button等中使用.我想仅在文本控件是此命令的目标时启用它.如何根据MVVM正确地做到这一点?

更多细节:

图图

窗口的XAML具有:

<Window.CommandBindings>
<CommandBinding Command="local:EditorCommands.WordWrap"
    Executed="WordWrapExecuted"
    CanExecute="CommandCanBeExecutedWhenAnythingIsOpen"/>
</Window.CommandBindings>
Run Code Online (Sandbox Code Playgroud)

菜单项以这种方式使用:

<MenuItem Command="local:EditorCommands.WordWrap"/>
Run Code Online (Sandbox Code Playgroud)

第一件事是Executed和CanExecute事件处理程序:它们在Window类中,虽然我理解MVVM是什么,逻辑应该只在ViewModel中.

而且,这些函数中的发送者是窗口的实例.为什么它不是命令的目标?

我应该为每个命令编写自己的RoutedUICommand后继吗?

wpf routed-commands mvvm

5
推荐指数
1
解决办法
1445
查看次数

WPF两个命令处理程序,一个命令

我来自第三方控制.它正在实现ApplicationCommands.SelectAll.但是我想要的行为略有不同.没有我可以覆盖的虚方法,当我注册类处理程序时,就像这样

     CommandManager.RegisterClassCommandBinding(typeof(MyDerivedControl), new CommandBinding(ApplicationCommands.SelectAll, new ExecutedRoutedEventHandler(OnExecutedSelectAll), new CanExecuteRoutedEventHandler(OnCanExecuteSelectAll)));
Run Code Online (Sandbox Code Playgroud)

我的方法没有被调用.我得出的第三方控制是标记

e.Handled=true;

在它的命令处理程序(我知道这个原因,我已经看到了源,但我不能修改它)

我能做什么?

wpf command routed-commands commandbinding

4
推荐指数
1
解决办法
2314
查看次数

我必须使用CommandTarget吗?我认为任何有针对性的元素都会收到命令

我正在尝试了解如何使用RoutedCommands.我的印象是,如果我没有在Button上指定CommandTarget,任何聚焦元素都将收到命令.但由于某种原因,它不起作用.这是不起作用的xaml:

<Window x:Class="WpfTest11_Commands2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Height="177" HorizontalAlignment="Left"
            Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="233" AcceptsReturn="True" />
        <TextBox Height="177" HorizontalAlignment="Left"
            Margin="258,12,0,0" Name="textBox2" VerticalAlignment="Top" Width="233" AcceptsReturn="True" />
        <Button Content="Cut"
                    Height="23" HorizontalAlignment="Left" Margin="12,195,0,0" Name="button1" VerticalAlignment="Top" Width="75"
                    Command="ApplicationCommands.Cut"/>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

如果我将CommandTarget添加到Button它可以工作,但仅适用于当然指定的文本框.

<Window x:Class="WpfTest11_Commands2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Height="177" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="233" AcceptsReturn="True" />
        <TextBox Height="177" HorizontalAlignment="Left" Margin="258,12,0,0" Name="textBox2" VerticalAlignment="Top" Width="233" AcceptsReturn="True" />
        <Button Content="Cut"
                    Height="23" HorizontalAlignment="Left" Margin="12,195,0,0" Name="button1" VerticalAlignment="Top" Width="75"
                    Command="ApplicationCommands.Cut"
                    CommandTarget="{Binding ElementName=textBox1}"/>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

如何使任何聚焦元素接收命令?

谢谢!

wpf xaml routed-commands

4
推荐指数
1
解决办法
2671
查看次数

WPF - 为什么ContextMenu项目适用于ListBox而不适用于ItemsControl?

列表中的项目具有上下文菜单.上下文菜单项绑定到路由命令.

如果列表控件是a ListBox,则上下文菜单项可正常工作,但是一旦我将其降级为ItemsControl不再有效,它就会正常工作.具体来说,菜单项始终是灰色的.CanExecute我的回调CommandBinding也没有被调用.

它是什么ListBox允许上下文菜单项与命令正确绑定?

以下是一些示例应用程序的摘录,我将它们放在一起以突出显示问题:

<!-- Data template for items -->
<DataTemplate DataType="{x:Type local:Widget}">
  <StackPanel Orientation="Horizontal">
    <StackPanel.ContextMenu>
      <ContextMenu>
        <MenuItem Header="UseWidget" 
                  Command="{x:Static l:WidgetListControl.UseWidgetCommand}"
                  CommandParameter="{Binding}" />
      </ContextMenu>
    </StackPanel.ContextMenu>
    <TextBlock Text="{Binding Path=Name}" />
    <TextBlock Text="{Binding Path=Price}" />
  </StackPanel>
</DataTemplate>

<!-- Binding -->
<UserControl.CommandBindings>
  <CommandBinding Command="{x:Static l:WidgetListControl.UseWidgetCommand}" 
                  Executed="OnUseWidgetExecuted" 
                  CanExecute="CanUseWidgetExecute" />
</UserControl.CommandBindings>

<!-- ItemsControl doesn't work... -->
<ItemsControl ItemsSource="{Binding Path=Widgets}" />

<!-- But change it to ListBox, and it works! -->
<ListBox ItemsSource="{Binding Path=Widgets}" />
Run Code Online (Sandbox Code Playgroud)

这是视图模型和数据项的C#代码: …

.net wpf listbox itemscontrol routed-commands

3
推荐指数
1
解决办法
5948
查看次数

如何覆盖 WPF 文本框上的复制命令?

我想重写 WPF 文本框的 RoutedUICommand“复制”行为。

是否可以不创建一个继承自 TextBox 的新 TextBoxExtended 类?

我已经达到了这一点,但现在我有点迷失了。

Private Sub tbSource_PreviewExecuted(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        Dim commandName = DirectCast(e.Command, Input.RoutedUICommand).Text

        If commandName = "Copy" Then

        End If

End Sub
Run Code Online (Sandbox Code Playgroud)

您知道如何继续吗?

routed-commands wpf-controls

3
推荐指数
1
解决办法
3617
查看次数

是否可以让CommandManager重新查询特定的WPF命令而不是全部?

我正在尝试为我的MVVM应用程序实现高度响应的UI,因此我选择让所有命令处理程序自动执行,BackgroundWorker以便它们不会阻止UI.

但与此同时,我不希望用户在后台执行时仍能执行相同的命令.解决方案似乎很明显:

  1. Executed调用处理程序,有CanExecute处理程序返回false
  2. 启动BackgroundWorker异步
  3. BackgroundWorker完成后,有CanExecute处理程序返回true一次.

问题是,我需要在步骤1之后通知WPF,然后在步骤3之后再次通知WPF CanExecute,并且应该是必需的.我知道我可以通过调用来完成它CommandManager.InvalidateRequerySuggested,但这会导致CanExecute所有其他命令的处理程序被重新查询.有很多命令,这不好.

有没有办法要求重新查询特定命令 - 即当前正在执行的命令?

TIA

wpf user-interface routed-commands mvvm

3
推荐指数
1
解决办法
1615
查看次数

WPF - 自定义控件 + ICommand(如何实现)?

基本上,我有一个自定义控件FooControl

public class FooControl : ItemsControl
{
    //Code
}
Run Code Online (Sandbox Code Playgroud)

我需要添加一些事件处理,但我更喜欢使用 Commanding,而不是使用 RoutedEvent。但我不太确定如何去做这件事。如果我想要它,那么当 Bar1Property (DependencyProperty) 更改时,它会引发 Execute 关联的执行属性。我通过 .NET Reflector 查看了 ButtonBase 代码,哇,这看起来太复杂了。添加命令这么复杂吗?显然,我还必须做到这一点,以便我的控件根据 CanExecuteChanged 是否更改来启用/禁用其自身的某些部分。但我想那是另一部分。

这是到目前为止我的 OnBar1Changed 函数......

    private static void OnBar1Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        FooControl element = (FooControl)obj;
        //What to do here?
    }
Run Code Online (Sandbox Code Playgroud)

wpf custom-controls routed-commands icommand

3
推荐指数
1
解决办法
5221
查看次数

在PreviewExecuted之后执行未被调用

这是我的代码:

var commandBinding = new CommandBinding(ApplicationCommand.New);
commandBinding.PreviewExecuted += OnPreviewExecuted;
commandBinding.Executed += OnExecuted;
CommandBindings.Add(commandBinding);

void OnPreviewExecuted(object sender, ExecutedRoutedEventArgs e) {
  e.Handled = false;
}

void OnExecuted(object sender, ExecutedRoutedEventArgs e) {
  DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

MSDN说:"......如果未处理预览事件,则会在命令目标上引发Executed事件."

这对PreviewCanExecute事件可以正常工作.但在这种情况下,当PreviewExecuted-Event正在侦听时,不会调用Executed-Event.

我没有找到关于这个主题的任何内容,所以我想问一下,这个行为是有意还是不正确.

c# wpf routed-commands

3
推荐指数
1
解决办法
568
查看次数

使用 Prism 库将 ListView 项传递给命令

我正在尝试根据列表视图项目数据执行方法。除此之外,触发命令的按钮应该只在列表视图项的“CanExecute”方法返回 true 时启用。

“MyCommand”和“CanExecute”这两种方法都包含在我的 ViewModel 中。不幸的是,我不确定如何将项目信息正确地传递给这两种方法以符合 PRISM 6 框架。

所以我的第一种方法是这样做:

模型

public class MyModel
{
    public string Name { get; set; }
    public string Version { get; set; }
    public int Identifier { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

public class MyViewModel : BindableBase
{

    private ObservableCollection<MyModel> _models = new ObservableCollection<MyModel>();
    public ObservableCollection<MyModel> Models
    {
        get { return _models; }
        set { SetProperty(ref _models, value); }
    }

    public DelegateCommand VerifyCommand { get; set; }


    public MyViewModel()
    {
        //Add test data
        for …
Run Code Online (Sandbox Code Playgroud)

c# prism routed-commands mvvm

3
推荐指数
1
解决办法
3487
查看次数

手动执行WPF路由命令

RoutedUICommand从代码隐藏手动执行自定义时,如下所示:

MyCommands.MyCommand.Execute(parameter, target)
Run Code Online (Sandbox Code Playgroud)

我需要先调用CanExecute方法还是已经在Execute方法中完成了?

c# wpf routed-commands

2
推荐指数
1
解决办法
3621
查看次数

带参数的RoutedCommand

我正在玩RoutedCommand,我遇到了一个问题,我找到了如何传递一个参数,以便我的Executed方法可以在e.Parameter中使用它?

我的路由命令:

public static readonly RoutedCommand Foo = new RoutedCommand();
Run Code Online (Sandbox Code Playgroud)

用法:

menuItem.Command = Commands.Foo;
Run Code Online (Sandbox Code Playgroud)

执行:

private void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            object parameter = e.Parameter; // this is always null
        }
Run Code Online (Sandbox Code Playgroud)

c# wpf routed-commands c#-4.0

2
推荐指数
1
解决办法
3562
查看次数