我是 MVVM 模式的新手。
我想知道为什么每次触发我的 TextChanged()
事件时,绑定(bind)的 IsEnabled()
属性都不会更改其状态。 TextChanged()
事件正在调用 IsValid()
来检查数据有效性。
我有这个简单的 ViewModel
类
public class myViewModel : ViewModel
{
public bool IsOk { get; set; }
public RelayCommand OnValidateExecute { get; set; }
public myViewModel()
{
OnValidateExecute = new RelayCommand(p => IsValid(), p => true);
}
public bool IsValid()
{
// other codes
IsOk = MethodName();
NotifyPropertyChanged("IsOk");
}
}
我在 IsValid()
上设置了一个断点,代码运行正常。我想知道为什么 IsEnabled
属性没有按预期工作。
这是我的XAML
代码
<TextBox ...other propeties here....>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding OnValidateExecute}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Button x:Name="btnSave" IsEnabled="{Binding IsOk, Mode=TwoWay}"
...other propeties here....>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding OnSaveExecute}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
我想要的是,当 IsOk
属性为 false 时,按钮应该是 Disabled
,否则,Enabled
。
我的数据绑定(bind)有问题吗?如果以前有人问过这个问题,请帮助我重定向到它。
更新 1
我在这段代码中遇到的另一个问题是,IsValid()
函数在文本框上设置值之前首先被触发。这是一个示例,假设文本框的起始值为 0
,当我将其更改为 9 时,将要检查的值是先前的值 0
> 而不是 9
。知道为什么会这样吗?绑定(bind)有问题吗?
最佳答案
这是答案,包括我的 MVVM 框架的重要部分。除此之外,我在上面添加了一些额外的功能。我不能把我所有的图书馆都放在这里。但我相信它会有所帮助。
如果您使用命令,您应该知道 ICommand
接口(interface)中的 CanExecuteChanged
。您应该在属性更改时触发此命令。 (我不使用 RelayCommand,它是 3.party 。)
使用我的 DCommand :) 这是最重要的部分
它很容易实现,
并具有 FirePropertyChanged
方法。如果 ICommand 不为空,此方法将触发 CanExecuteChanged
。
一个示例命令
匿名语法
DCommand commandPost=new DCommand(()=>{
//TODO:Command's real execute method Post()
},
()=>
{
return this.TextBoxBoundProperty.IsValid;
}
)
非匿名语法
DCommand commandPost=(Post,Validate);
除此之外,您应该通过 viewModel 构造函数中的以下方法触发 canexecutechanged。
this.PropertyChanged += (sender, prop) =>
{
//I preffered canExcuteChange for any property changes for my viewmodel class. You could put your own logic. if(prop.PropertyName.equals("thisone"));
//Just works for this class's property changed
this.InvokeOnClassPropertyChange(prop.PropertyName, () =>
{
this.commandPost.FirePropertyChanged();
});
}
如果属性是 ViewModel 类的属性,InvokeOnClassPropertyChange 起作用。
public static void InvokeOnClassPropertyChange(this object instance,string PropertyName,Action action)
{
Type type = instance.GetType();
var fulllist = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(w => w.DeclaringType == type).ToList();
if (fulllist.Select(p => p.Name).Contains(PropertyName))
{
action.Invoke();
}
}
上面的代码显示了 InvokeOnClassPropertyChange
扩展方法。
下面显示了我的 DCommand
实现 ICommand。
public class DCommand :ICommand
{
public void FirePropertyChanged()
{
if (CanExecuteChanged!=null)
CanExecuteChanged(this, EventArgs.Empty);
}
Func<bool> CanExecuteFunc { get; set; }
Action<object> Action { get; set; }
public DCommand(Action<object> executeMethod)
{
this.Action = executeMethod;
}
public DCommand(Action executeMethod)
{
this.Action = new Action<object>(
(prm) =>
{
executeMethod.Invoke();
}
);
}
public DCommand(Action<object> executeMethod, Func<bool> canExecuteMethod)
: this(executeMethod)
{
this.CanExecuteFunc = canExecuteMethod;
}
public DCommand(Action executeMethod, Func<bool> canExecuteMethod)
: this(executeMethod)
{
this.CanExecuteFunc = canExecuteMethod;
}
public bool CanExecute(object parameter=null)
{
if (CanExecuteFunc == null)
return true;
return CanExecuteFunc.Invoke();
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter=null)
{
if (CanExecuteFunc == null || CanExecute(parameter))
{
Action.Invoke(parameter);
}
}
}
毕竟, 如果您想在文本框的文本立即更改时更改您的 ViewModel 属性,您应该通过这种方式进行绑定(bind)。
Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
关于c# - 绑定(bind) Button.IsEnabled() 属性无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16805163/