WPF MVVM - 带文本框的简单绑定按钮(Icommand)
Posted
技术标签:
【中文标题】WPF MVVM - 带文本框的简单绑定按钮(Icommand)【英文标题】:WPF MVVM - Simple Binding Button with Textbox (Icommand) 【发布时间】:2019-03-04 14:42:40 【问题描述】:我要做的是:当文本框包含值“123”时,它应该启用按钮并允许我单击它。
Solution Image & View Image
我找不到根据我的 Button 参数触发 Button 命令(名为 SpecialCommand.cs 的类)的方法。你能支持我在哪里弄错了这个 MVVM 模式吗?
WPF 视图 [MainWindow.xaml]:
<Window.Resources>
<ViewModel:MainWindowVM x:Key="WindowVm"></ViewModel:MainWindowVM>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox x:Name="textBox" Margin="0, 5" Text="123"/>
<Button Content="Click me!" Margin="0, 5" Command="Binding SpecialCommand, Source=StaticResource WindowVm" CommandParameter="Binding Text, ElementName=textBox, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay"/>
</StackPanel>
</Grid>
ViewModel [MainWindowVM.cs]:
public class MainWindowVM
private SpecialCommand _specialCommand;
public SpecialCommand SpecialCommand get => _specialCommand; set => _specialCommand = value;
public MainWindowVM()
_specialCommand = new SpecialCommand();
命令 [SpecialCommand.cs]
public class SpecialCommand : ICommand
public bool CanExecute(object parameter)
if (parameter != null && (parameter as string) == "123")
return true;
return false;
public void Execute(object parameter)
MessageBox.Show("Button Pressed!");
public event EventHandler CanExecuteChanged;
我相信,也许这就是我弄错了,因为按钮和文本框在视图中,我不需要在我的 SpecialCommand 实现中添加/修改任何方法。他们应该能够看到属性何时更改。 就像下面的 CanExecuteChanged() 一样,这个命令会引发很多次,对于这个小任务来说似乎有点过分了。
public event EventHandler CanExecuteChanged
add CommandManager.RequerySuggested += value;
remove CommandManager.RequerySuggested -= value;
【问题讨论】:
【参考方案1】:没有必要让它变得比需要的更复杂。
public class MainWindowVM
private string m_OneTwoThree;
public string OneTwoThree
get return OneTwoThree;
set
if (m_OneTwoThree != value)
m_OneTwoThree = value;
NotifyPropertyChanged(nameof(OneTwoThree)); //if you need this let me know
public MainWindowVM()
public ICommand RandomCommand get return new RelayCommand(OnRandom, IsOneTwoThree);
private void OnRandom()
//do stuff
private bool IsOneTwoThree()
if (OneTwoThree == "123")
return true;
return false;
您还必须更新您的xaml
我认为它无法找到“OneTwoThree”,因此您必须自己绑定它,但您通常会这样做。
<StackPanel>
<TextBox x:Name="textBox" Margin="0, 5" Text="Binding OneTwoThree"/>
<Button Content="Click me!" Margin="0, 5" Command="Binding RandomCommand, Source=StaticResource WindowVm"/>
</StackPanel>
如果您有任何问题,请随时提出。
这是我的 RelayCommand :使用 RelayCommand("要执行的东西", "如果函数返回 true 你可以执行");
public class RelayCommand : ICommand
public event EventHandler CanExecuteChanged
add CommandManager.RequerySuggested += value;
remove CommandManager.RequerySuggested -= value;
private Action methodToExecute;
private Func<bool> canExecuteEvaluator;
public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
this.methodToExecute = methodToExecute;
this.canExecuteEvaluator = canExecuteEvaluator;
public RelayCommand(Action methodToExecute)
: this(methodToExecute, null)
public bool CanExecute(object parameter)
if (this.canExecuteEvaluator == null)
return true;
else
bool result = this.canExecuteEvaluator.Invoke();
return result;
public void Execute(object parameter)
this.methodToExecute.Invoke();
【讨论】:
嗨,马特,感谢您的回复。我喜欢你的 RelayCommand 实现。是的,它按预期工作,没有任何奇怪的行为,如以前的答案。我唯一认为这会在我的代码中创建另外两个额外的方法,但如果这是最好的方法,我将从现在开始使用它。 我唯一不明白的是为什么我们有 CanExecute: 对象参数。看起来我们不需要这个参数,也没有办法将它与 Button CommandParameter = "" 一起实际使用。CanExecute
检查IsOneTwoThree()
是否返回 true 或 false,如果为 true,则启用按钮,如果为 false,则禁用按钮。
您不需要使用CommandParameter
,因为TextBox
已绑定到ViewModel
上的OneTwoThree
字段,我们只需检查OneTwoThree == "123"
上的字段是否为OneTwoThree == "123"
还用NotifyPropertyChanged
更新了代码【参考方案2】:
你需要一种方法来告诉命令它应该检查它是否CanExecute
。这是通过触发事件CanExecuteChanged
来完成的。它告诉按钮重新查询CanExecute
属性。
为此,我将向您的视图模型添加一个文本属性并将文本框绑定到它。
在SpecialCommand
中添加方法:
public void TriggerCanExecuteChanged()
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
在MainWindowVM
类中添加属性:
private string _text;
public string Text
get return _text;
set
if (value != _text)
_text = value;
_specialCommand.TriggerCanExecuteChanged();
查看模型以实现INotifyPropertyChanged
(参见 cmets):
public class MainWindowVM : INotifyPropertyChanged
public SpecialCommand SpecialCommand get; set; = new SpecialCommand();
private string _text;
public string Text
get return _text;
set
if (value != _text)
_text = value;
OnPropertyChanged(nameof(Text));
SpecialCommand.TriggerCanExecuteChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
【讨论】:
嗨奥利弗,感谢您的回复。我已经尝试过您的代码,但我遇到了问题。看起来如果我引发/触发 TriggerCanExecuteChanged() 方法,则 SpecialCommand 正在接收的值与属性本身之间存在延迟。我这里有什么,我需要输入“1234”,这样它就会升起并启用我的按钮。 我做了另一个测试,看起来我的 Button 在属性值更改之前接收到旧参数。也许这张图片会更好地解释问题是什么:imgur.com/3eNldov。新值为 1234,旧值为 _text = "123"。所以参数是一个延迟的文本属性结果。很奇怪? 不使用此参数,您可以将 VM 的引用传递给命令并使用Text
属性。在文本框中使用UpdateSourceTrigger=PropertyChanged
。如果你不这样做,按钮可能只会在验证时更新,即在离开 thextbox 之后。您还可以让 VM 实现 INotifyPropertyChanged
和 Text
属性在更改时触发 PropertyChanged
事件。如果您希望对 VM 的更改立即反映在文本框中,这是必要的。以上是关于WPF MVVM - 带文本框的简单绑定按钮(Icommand)的主要内容,如果未能解决你的问题,请参考以下文章