如何使用 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>
我正在使用 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>