wpf 使用MVVM Community Toolkit,如何将UserControl事件绑定到RelayCommand

vwkv1x7d  于 2023-06-24  发布在  其他
关注(0)|答案(1)|浏览(172)

我尝试自定义WPF TextBox,以便在用户在用户界面中进行更改时引发事件(但不是在编程方面,所以不使用OnPropertyChanged)。目标也是将这种方法扩展到其他控件,如NumericUpDown等。
下面是我的代码:

<TextBox x:Class="WFP_vs_winform_control.validated.MyTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</TextBox>

    public partial class MyTextBox : TextBox
    {
        private bool userChange = false;    
        public event EventHandler UserMadeChange;  
        public MyTextBox()
        {
            InitializeComponent();
        }

        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            userChange = true;
            base.OnPreviewTextInput(e);
        }
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            if (userChange) UserMadeChange?.Invoke(this, e);
            base.OnLostFocus(e);
            userChange = false;
        }

<Window x:Class="WFP_vs_winform_control.validated.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WFP_vs_winform_control.validated"
        mc:Ignorable="d"
        Title="Test MyTextBox" Height="200" Width="350">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <StackPanel>
        <local:MyTextBox Text="{Binding MyText,UpdateSourceTrigger=LostFocus}" UserMadeChange="{Binding SaveCommand}" Margin="10" />
            <Label Content="{Binding MyText}"/>
            <Button Content="cancel" Command="{Binding CancelCommand}"  Margin="10"/>
    </StackPanel>
    
</Window>

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WFP_vs_winform_control.validated
{
    internal partial class ViewModel : ObservableObject
    {
        [ObservableProperty] string myText = string.Empty;
        public ViewModel()
        {
        }

        [RelayCommand] private void Save()
        {
            MessageBox.Show("Procedure to save data");
        }
        [RelayCommand] private void Cancel()
        {
            MyText = string.Empty ;
            MessageBox.Show("Cancel");
        }
    }
}

问题是我无法执行UserMadeChange="{Binding SaveCommand}",因为它返回错误XLS 0523事件“UserMadeChange”只能绑定到委托类型“EventHandler”的属性。
你能帮忙吗?先谢谢你了。
我试图找到如何绑定到RelayCommand在幕后工作,但没有发现这么多的社区工具包没有接缝被广泛使用到目前为止。

ljsrvy3e

ljsrvy3e1#

好吧,谢谢Emoacht,我得到了一些工作。但它仍然不够通用。如何从MainWindow中删除Interaction触发器以将其放入MyTextBox?

<Window x:Class="WFP_vs_winform_control.validated.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:WFP_vs_winform_control.validated"
    mc:Ignorable="d"
    Title="Test MyTextBox" Height="200" Width="350">
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
<StackPanel>
    <local:MyTextBox Text="{Binding MyText,UpdateSourceTrigger=LostFocus}" Margin="10">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="UserMadeChange">
                <i:InvokeCommandAction Command="{Binding SaveCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </local:MyTextBox>
    <Label Content="{Binding MyText}"/>
    <Button Content="cancel" Command="{Binding CancelCommand}"  Margin="10"/>
</StackPanel>
internal partial class ViewModel : ObservableObject
{
    [ObservableProperty] string myText = string.Empty;
    public ViewModel() { }

    [RelayCommand] private void Save()
    {
        MessageBox.Show("Procedure to save data");
    }
    [RelayCommand] private void Cancel()
    {
        MyText = string.Empty ;
        MessageBox.Show("Cancel");
    }
    public void SaveUserChange(object sender, EventArgs e)
    {
        MessageBox.Show("save");
    }

}

<TextBox x:Class="WFP_vs_winform_control.validated.MyTextBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
public partial class MyTextBox : TextBox
{
    private bool userChange = false;    
    public event RoutedEventHandler UserMadeChange;
    //public ICommand UserChangeCommand { get; set; }

    public MyTextBox()
    {
        InitializeComponent();
    }

    protected override void OnLostFocus(RoutedEventArgs e)
    {
        if (userChange)
        {
            UserMadeChange?.Invoke(this, e);
            userChange = false;
        }
        base.OnLostFocus(e);
    }
    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.Enter:
            case Key.Tab:
                if (userChange)
                {
                    userChange = false;
                    UserMadeChange?.Invoke(this, e);
                }
                return;
            case Key.Left: 
            case Key.Right:
            case Key.Up: 
            case Key.Down:
            case Key.PageUp:
            case Key.PageDown:
            case Key.Home: 
            case Key.End:
            case Key.LeftCtrl: 
            case Key.RightCtrl:
            case Key.LeftShift: 
            case Key.RightShift:
            case Key.CapsLock:
            case Key.LeftAlt: 
            case Key.RightAlt:
            case Key.LWin: 
            case Key.RWin:
            case Key.Apps:
            case Key.Escape:
                base.OnPreviewKeyDown(e);
                return;
            default:
                userChange = true;
                base.OnPreviewKeyDown(e);
                return;
        }
    }
}

相关问题