我想了解在处理许多属性时如何正确使用MVVM和数据绑定。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="463" Text="{Binding OriginalText, UpdateSourceTrigger=PropertyChanged}" />
<Label Height="28" HorizontalAlignment="Left" Margin="12,242,0,0" Name="label1" VerticalAlignment="Top" Width="463" Content="{Binding ModifiedText}"/>
<CheckBox Content="Upper" Height="16" HorizontalAlignment="Left" Margin="12,41,0,0" Name="checkBox1" VerticalAlignment="Top" />
<CheckBox Content="Underline" Height="16" HorizontalAlignment="Left" Margin="12,63,0,0" Name="checkBox2" VerticalAlignment="Top" />
<CheckBox Content="Bold" Height="16" HorizontalAlignment="Left" Margin="12,85,0,0" Name="checkBox3" VerticalAlignment="Top" />
<CheckBox Content="Shadow" Height="16" HorizontalAlignment="Left" Margin="12,107,0,0" Name="checkBox4" VerticalAlignment="Top" />
<CheckBox Content="Red" Height="16" HorizontalAlignment="Left" Margin="12,129,0,0" Name="checkBox5" VerticalAlignment="Top" />
<CheckBox Content="Scary" Height="16" HorizontalAlignment="Left" Margin="12,151,0,0" Name="checkBox6" VerticalAlignment="Top" />
<CheckBox Content="Remove first letter" Height="16" HorizontalAlignment="Left" Margin="12,173,0,0" Name="checkBox7" VerticalAlignment="Top" />
<CheckBox Content="Remove last letter" Height="16" HorizontalAlignment="Left" Margin="12,195,0,0" Name="checkBox8" VerticalAlignment="Top" />
</Grid>
我有一个OriginalText TextBox和一个ModifiedText标签。当我选中一个方框时,我想直接应用修改而无需单击按钮。我该怎么做?
在我的ViewModel中,我创建了绑定到XAML CheckBox的所有属性。
private string _originalText = string.Empty;
public string OriginalText
{
get { return _originalText; }
set
{
_originalText = value;
NotifyPropertyChanged("OriginalText");
}
}
private string _modifiedText;
public string ModifiedText
{
get { return _originalText; }
set
{
_originalText = value;
NotifyPropertyChanged("ModifiedText");
}
}
private bool upper;
public bool Upper
{
get { return upper; }
set
{
upper = value;
NotifyPropertyChanged("Upper");
// Should I notify something else here or call a refresh method?
}
}
private bool removeFirstLetter;
public bool RemoveFirstLetter
{
get { return removeFirstLetter; }
set
{
removeFirstLetter = value;
NotifyPropertyChanged("RemoveFirstLetter");
// Should I notify something else here or call a refresh method?
}
}
// ...
此时我在同一个ViewModel类中创建了一个Work方法。我稍后会将此方法转移到业务中。
private void Work()
{
string result = _originalText;
if (Upper)
result = result.ToUpper();
if (removeFirstLetter)
result = result.Substring(1, result.Length);
// if ...
ModifiedText = result;
}
我的问题是何时,我应该在哪里调用工作方法?我应该在每个安装者或吸气器中给它打电话吗?我不喜欢这个主意。我做错了什么......
谢谢。
答案 0 :(得分:1)
在您的特定情况下,您应该使用INotifyPropertyChanged接口创建一个布尔属性。现在将此属性绑定到“IsChecked”复选框属性。通过在setter中调用Work()方法,每次勾选“复选框”时,每次都会触发setter。
答案 1 :(得分:0)
您的问题的答案非常简单:使用Commands
。
命令是MVVM实现绑定到ViewModel中方法的方法。命令的实现遵循非常标准的模式。您可以在互联网上找到大量信息,这只是一个简短的草图:
在ViewModel中实现的命令必须是ICommand
类型,并且每个Command必须与代码中的方法一起执行实际方法,另一个方法用于检查当前是否可以执行
这些方法必须分别命名为CanExecute
和Execute
。通常情况下,使用名为DelegateCommand
的小帮助类来促进使用多个命令,该帮助类为前面提到的方法提供委托。
无需任何修改即可按照此类进行操作:
public class DelegateCommand<T> : ICommand {
private Predicate<T> canExecute;
private Action<T> execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand (Predicate<T> canExecute, Action<T> execute) {
this.canExecute = canExecute;
this.execute = execute;
}
public bool CanExecute (object param) {
return canExecute((T)param);
}
public void Execute (object param) {
execute((T)param);
}
public void CanExecuteChangedRaised () {
CanExecuteChanged(this, new EventArgs());
}
}
然后您的Command声明属于DelegateCommand
类型,而不是类型ICommand
。请参阅以下示例进行说明,您将了解到这一点:
假设您希望通过单击按钮调用ViewModel中的方法foo():
class ViewModel {
// ...
public DelegateCommand<object> FooCommand { get; set; }
public ViewModel () {
FooCommand = new DelegateCommand<object>(CanExecuteFooCommand, ExecuteFooCommand);
}
public bool CanExecuteFooCommand (object param) {
return true;
}
public void ExecuteFooCommand (object param) {
foo();
}
// ...
}
假设您已将ViewModel设置为控件DataContext
,通过它的DataContext
属性,唯一要做的就是将FooCommand
绑定到您的按钮,如下所示:
就是这样!
附录(参见评论):
为了在没有实际按下Button的情况下执行某些操作,您只需要使用ViewModel跟踪UI中的任何更改并做出相应的反应 - 这就是MVVM的用途:跟踪UI中的数据修改或处理它们并将它们填充回用户界面。
要对TextBox文本更改做出反应,请在ViewModel中创建相应的字符串属性,并跟踪View中新的ioncoming值是否与当前textBox文本不同:
private string _text;
public string Text {
get { return _text; }
set {
// the text in the TextBox is about to change.
if (!_text.Equals(value))
{
doSomething();
}
_text = value;
FirePropertyChanged("Text");
}
}
为了对你的CheckBox做同样的事情,你可以按照上面的描述应用ICommand,因为CheckBox是从Button派生的,因此提供了Command属性。