英文:
Using RelayCommand CanExecute with CommunityToolkit.MVVM and Microsoft.Xaml.Behaviors.Wpf
问题
我正在尝试将 CommunityToolkit.MVVM (8.2.0) 与 Microsoft.Xaml.Behaviors.Wpf (1.1.39) 结合使用,并使用 RelayCommands CanExecute 功能来启用/禁用按钮。
在我的情况下,我需要查询 PreviewMouseDown 事件(而不是标准的点击事件),这可以通过 EventTrigger 很好地实现。不幸的是,使用 Behavior 时按钮的开/关状态在视觉上没有显示出来,但按钮的功能确实已正确启用/禁用。
我希望具有 EventTrigger 的按钮的行为与没有 EventTrigger 的按钮相同。我对 WPF 还很陌生,请原谅我 ![]()
以下是 View.xaml(代码部分为空):
<Window x:Class="Example.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Example"
        mc:Ignorable="d"
        Title="View" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
  <Window.DataContext>
    <local:ViewModel/>
  </Window.DataContext>
  <StackPanel Margin="5" Orientation="Horizontal">
    <Button Command="{Binding ToggleAllowenceCommand}" Content="Toggle Allowence"/>
    
    <StackPanel Margin="5,0,0,0">
      
      <Button Command="{Binding MouseDownCommand}">
        <TextBlock Text="Button without xaml.behaviors"/>
      </Button>
      
      <Button Margin="0,5,0,0">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="PreviewMouseDown">
            <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
          </i:EventTrigger>
        </i:Interaction.Triggers>
        <TextBlock Text="Button with xaml.behaviors"/>
      </Button>
      
    </StackPanel>    
  </StackPanel>
</Window>
ViewModel.cs:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Example;
partial class ViewModel : ObservableObject
{
  public ViewModel() { }
  [ObservableProperty]
  [NotifyCanExecuteChangedFor(nameof(MouseDownCommand))]
  private bool _allowence = false;
  private bool CanExecuteMouseDown() => Allowence;
  [RelayCommand(CanExecute = nameof(CanExecuteMouseDown))]
  private void MouseDown() { }
  [RelayCommand]
  private void ToggleAllowence() => Allowence = !Allowence;
}
我尝试过向具有 EventTrigger 的按钮添加命令绑定,就像我在第一个按钮中所做的那样,但是某种方式看起来不对,或者我错了吗?后来,我想绑定更多的 EventTrigger,比如 PreviewMouseUp,所以似乎我不能避免将 Behaviors 与 MVVM 结合使用?
英文:
I am trying to combine the CommunityToolkit.MVVM (8.2.0) with Microsoft.Xaml.Behaviors.Wpf (1.1.39) and enable/disable a button using RelayCommands CanExecute functionality.
In my case I need to query the PreviewMouseDown event (Not a standard click event), this works quite well with an EventTrigger. Unfortunately, the on/off state is not visually displayed for the button with Behavior - but the functionality of the button is indeed properly enabled/disabled.
I want the button with EventTrigger to behave the same as the one without. I am quite new to WPF, please forgive me ![]()
Here is the View.xaml (code behind is "empty"):
<Window x:Class="Example.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Example"
        mc:Ignorable="d"
        Title="View" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
  <Window.DataContext>
    <local:ViewModel/>
  </Window.DataContext>
  <StackPanel Margin="5" Orientation="Horizontal">
    <Button Command="{Binding ToggleAllowenceCommand}" Content="Toggle Allowence"/>
    
    <StackPanel Margin="5,0,0,0">
      
      <Button Command="{Binding MouseDownCommand}">
        <TextBlock Text="Button without xaml.behaviors"/>
      </Button>
      
      <Button Margin="0,5,0,0">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="PreviewMouseDown">
            <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
          </i:EventTrigger>
        </i:Interaction.Triggers>
        <TextBlock Text="Button with xaml.behaviors"/>
      </Button>
      
    </StackPanel>    
  </StackPanel>
</Window>
ViewModel.cs:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Example;
partial class ViewModel : ObservableObject
{
  public ViewModel() { }
  [ObservableProperty]
  [NotifyCanExecuteChangedFor(nameof(MouseDownCommand))]
  private bool _allowence = false;
  private bool CanExecuteMouseDown() => Allowence;
  [RelayCommand(CanExecute = nameof(CanExecuteMouseDown))]
  private void MouseDown() { }
  [RelayCommand]
  private void ToggleAllowence() => Allowence = !Allowence;
}
I experimented with adding a command binding to the button with the EventTrigger like I did with the first button - but somehow it looks wrong, or am I wrong? Later I wanted to bind more EventTriggers - like PreviewMouseUp, so it seems I can't avoid Behaviors in combination with MVVM?
答案1
得分: 2
很不幸,按钮的开/关状态在 Behavior 中没有进行视觉显示,但确实已正确启用/禁用按钮的功能。
这是预期的行为。如此博客文章所述," InvokeCommandAction 不会根据命令的 CanExecute 方法自动启用或禁用控件,不像具有 Command 属性并可以直接绑定到命令的控件。"
英文:
>Unfortunately, the on/off state is not visually displayed for the button with Behavior - but the functionality of the button is indeed properly enabled/disabled.
This is the expected behaviour. As stated in this blog post, "an InvokeCommandAction doesn't automatically enable or disable the control based on the command's CanExecute method, unlike controls that have a Command property and can be bound directly to a command."
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论