如何使用 ICommand 在 MVVM 中触发 TextChanged 事件

How to trigger TextChanged Event in MVVM with ICommand

我正在使用 2 个文本框。如果用户在其中一个文本框中键入内容,则另一个文本框将被禁用。如果用户删除其中一个文本框中的所有文本,另一个文本框将重新启用。

这些规则是为了确保只有一个文本框可以包含文本。 里面有文字的文本框是监听搜索按钮触发器的搜索文本框"Suchen".

视图如下所示:

为了使这些规则起作用,我想根据 MVVM 标准使用 TextChanged-Events 作为 ICommand。我试了一下,但它没有达到我想要的效果。 它有什么作用? - 如果我在 "Artikelbezeichnung"-textbox 中输入内容,"Lieferant"-textbox 将不会禁用,如果我删除 "Artikelbezeichnung" 中的所有文本,"Lieferant"-textbox 将禁用(并且永远不会重新启用)。我相信我无法理解这种奇怪行为的逻辑,这就是为什么我需要你的帮助。我将代码减少到最少,让您更轻松。

我需要更改什么才能使我的规则生效? 请看看下面的代码并帮助我。非常感谢您的尝试!

XAML-查看

 <StackPanel Height="423" VerticalAlignment="Bottom">
    <Label Name="lblArtikelbezeichnung" Content="Artikelbezeichnung:" Margin="20, 20, 20, 0"></Label>
    <TextBox Name="txtArtikelbezeichnung" 
             Width="Auto" 
             Margin="20, 0, 20, 0"
             IsEnabled="{Binding BezEnabled}"
             Text="{Binding BezText}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <i:InvokeCommandAction Command="{Binding TextChangedBez}" />
            </i:EventTrigger>
            <i:EventTrigger EventName="KeyUp">
                <i:InvokeCommandAction Command="{Binding KeyUpBez}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    <!--TextChanged="txtArtikelbezeichnung_TextChanged" 
             KeyUp="txtArtikelbezeichnung_KeyUp"-->
    <Label Name="lblLieferant" Content="Lieferant:" Margin="20, 0, 20, 0"></Label>
    <TextBox Name="txtLieferant" 
             Width="Auto" 
             Margin="20, 0, 20, 0"
             IsEnabled="{Binding LiefEnabled}"
             Text="{Binding LiefText}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <i:InvokeCommandAction Command="{Binding TextChangedLief}" />
            </i:EventTrigger>
            <i:EventTrigger EventName="KeyUp">
                <i:InvokeCommandAction Command="{Binding KeyUpLief}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
        <!--TextChanged="txtLieferant_TextChanged" 
             KeyUp="txtLieferant_KeyUp"-->
    <Button Name="btnSuchen" 
            Content="Suchen" 
            Width="100" Height="25" 
            Margin="20, 10,240, 10" 
            Command="{Binding GefilterteSuche}">
    </Button>
...
<StackPanel>

代码隐藏

 using System.Windows;

namespace Lieferscheine
{
    /// <summary>
    /// Interaktionslogik für artikelHinzu.xaml
    /// </summary>
    public partial class artikelHinzu : Window
    {

        public artikelHinzu()
        {
            InitializeComponent();
            DataContext = new ArtikelHinzuViewModel();
        }     
    }
}

查看模型

public class ArtikelHinzuViewModel : INotifyPropertyChanged
{

    //ICommands
    public ICommand TextChangedLief => new DelegateCommand<object>(TextChangedLieferant);        
    public ICommand TextChangedBez => new DelegateCommand<object>(TextChangedBezeichnung);


    private bool _bezEnabled = true;
    private bool _liefEnabled = true;
    public bool BezEnabled
    {
        get
        {
            return _bezEnabled;
        }
        set
        {
            _bezEnabled = value;
            OnPropertyChanged("BezEnabled");
        }
    }
    public bool LiefEnabled
    {
        get 
        { 
            return _liefEnabled;
        }

        set
        {
            _liefEnabled = value;
            OnPropertyChanged("LiefEnabled");
        }
    }

    private string _bezText;
    private string _liefText;
    public string LiefText
    {
        get
        {
            return _liefText;
        }
        set
        {
            _liefText = value;
            OnPropertyChanged("LiefText");
        }
    }

    public string BezText
    {
        get
        {
            return _bezText;
        }
        set
        {
            _bezText = value;
            OnPropertyChanged("BezText");
        }
    }

    public void TextChangedBezeichnung(object param)
    {
        if (!String.IsNullOrWhiteSpace(BezText))
        {
            LiefEnabled = false;
        }
        else
        {
          LiefEnabled = true;
        }
    }

    public void TextChangedLieferant(object param)
    {
        if (!String.IsNullOrWhiteSpace(LiefText))
        {
           BezEnabled = false;
        }
        else
        {
            BezEnabled = true;
        }
    }
public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    //Konstruktor
    public ArtikelHinzuViewModel()
    {

    }
}

我认为不良行为是由 Event Racing 引起的。

请注意,数据绑定机制 by default 在绑定目标(UI 元素)的 LostFocus 上调用文本 属性 的 setter。但是在 TextBox 失去焦点之前 TextChanged 事件已经被触发。这会导致您的命令无法产生正确的逻辑。

一个快速的解决方案是

Text="{Binding BezText, UpdateSourceTrigger=PropertyChanged}">

当然我不知道你的具体情况,但我认为即使在MVVM意义上也没有必要使用ICommand和System.Windows.Interactivity。您可以考虑以下内容:

视图模型

        public string LiefText
        {
            get
            {
                return _liefText;
            }
            set
            {
                _liefText = value;
                OnPropertyChanged("LiefText");

                if (!String.IsNullOrWhiteSpace(_liefText))
                    BezEnabled = false;
                else
                    BezEnabled = true;
            }
        }

        public string BezText
        {
            get
            {
                return _bezText;
            }
            set
            {
                _bezText = value;
                OnPropertyChanged("BezText");

                if (!String.IsNullOrWhiteSpace(_bezText))
                    LiefEnabled = false;
                else
                    LiefEnabled = true;
            }
        }

查看

        <TextBox Name="txtArtikelbezeichnung" 
             Width="Auto" 
             Margin="20, 0, 20, 0"
             IsEnabled="{Binding BezEnabled}"
             Text="{Binding BezText, UpdateSourceTrigger=PropertyChanged}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="KeyUp">
                    <i:InvokeCommandAction Command="{Binding KeyUpBez}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>

       <TextBox Name="txtLieferant" 
             Width="Auto" 
             Margin="20, 0, 20, 0"
             IsEnabled="{Binding LiefEnabled}"
             Text="{Binding LiefText, UpdateSourceTrigger=PropertyChanged}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="KeyUp">
                    <i:InvokeCommandAction Command="{Binding KeyUpLief}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>