我的ViewModel中有类似的内容:
public enum WorkState
{
Idle, Working, Stopping
};
public class MainViewModel : ViewModelBase
{
public const string StatePropertyName = "State";
private WorkState _state = WorkState.Idle;
public WorkState State
{
get
{ return _state; }
set
{
if (_state == value)
{
return;
}
RaisePropertyChanging(StatePropertyName);
_state = value;
RaisePropertyChanged(StatePropertyName);
StartStopCommand.RaiseCanExecuteChanged(); // <—————————————
}
}
private RelayCommand _startStopCommand;
public RelayCommand StartStopCommand
{
get
{
return _startStopCommand
?? (_startStopCommand = new RelayCommand(
() =>
{
if (State == WorkState.Idle)
{
State = WorkState.Working;
}
else if (State == WorkState.Working)
{
State = WorkState.Stopping;
new Thread(() =>
{
Thread.Sleep(5000);
State = WorkState.Idle;
}).Start();
}
},
() => (State == WorkState.Idle ||
(State == WorkState.Working)));
}
}
}
我视图中的按钮:
<Button Command="{Binding StartStopCommand}">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Idle}">
<Setter Property="Button.Content" Value="Start"/>
</DataTrigger>
<DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Working}">
<Setter Property="Button.Content" Value="Stop"/>
</DataTrigger>
<DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Stopping}">
<Setter Property="Button.Content" Value="Stop"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
但是当我按下“停止”按钮并且“状态”属性更改为“空闲”时,按钮仅将其“文本”更改为“开始”,但在我单击窗口中的某个位置之前一直处于禁用状态。
我将RaiseCanExecuteChanged添加到State属性的setter中,但它没有帮助。
我做错了什么?
此外,我不确定在同一命令中使用Start / Stop和使用设置按钮文本的DataTriggers这种方法是最好的,所以如果有人分享更好的方法,我将不胜感激。
答案 0 :(得分:3)
此处的问题不是RaiseCanExecuteChanged()
无效,而是在您的用户界面依赖它时从后台线程修改State
属性。
所以说如果我相应地修改你的代码:(这是.Net 4.5)
public RelayCommand StartStopCommand { get; set; }
...
public MainViewModel() {
StartStopCommand = new RelayCommand(async () => {
switch (State) {
case WorkState.Idle:
State = WorkState.Working;
break;
case WorkState.Working:
State = WorkState.Stopping;
await Task.Delay(5000);
State = WorkState.Idle;
break;
}
}, () => State == WorkState.Idle || State == WorkState.Working);
}
现在,您可以看到Button
从禁用状态切换回正确启用。
您可以从Here
获取样本如果您想坚持使用Thread
,请将其切换为:
new Thread(
() => {
Thread.Sleep(5000);
Application.Current.Dispatcher.BeginInvoke(
new Action(() => State = WorkState.Idle));
}).Start();
^^现在再次正常工作,因为你没有从另一个线程修改属性。
答案 1 :(得分:1)
答案 2 :(得分:1)
我认为您必须通过State change
设置Dispatcher
。
请参阅此处了解如何执行此操作:
http://msdn.microsoft.com/en-US/magazine/cc163328.aspx#S3 - &gt; (图4更新UI)