我遇到MVVM-Light问题。我使用版本5.3.0.0 ...
.XAML
<DockPanel Dock="Top">
<Button Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" Command="{Binding CancelDownloadCommand}" FontSize="20"
Background="Transparent" BorderThickness="2" BorderBrush="{StaticResource AccentColorBrush4}" ToolTip="Cancelar"
DockPanel.Dock="Right">
<StackPanel Orientation="Horizontal">
<Image Source="Images/48x48/Error.png" Height="48" Width="48"/>
<Label Content="{Binding ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" FontFamily="Segoe UI Light"/>
</StackPanel>
</Button>
<Button Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" Command="{Binding DownloadCommand}" FontSize="20"
Background="Transparent" BorderThickness="2" BorderBrush="{StaticResource AccentColorBrush4}" ToolTip="Descargar"
DockPanel.Dock="Right">
<StackPanel Orientation="Horizontal">
<Image Source="Images/48x48/Download.png" Height="48" Width="48"/>
<Label Content="{Binding ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" FontFamily="Segoe UI Light"/>
</StackPanel>
</Button>
</DockPanel>
DownloadViewModel.cs
我使用了MessageBox,但在我的情况下,调用一个读取XML的方法。此示例不起作用,按钮被禁用,但在执行结束时不会重新激活。我需要点击UI激活。
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
private async void Download()
{
Reset();
await Task.Run(() =>
{
MessageBox.Show("Hello");
});
Reset();
}
private void Reset()
{
IsEnabled = !IsEnabled;
IsEnabledCancel = !IsEnabledCancel;
}
private ICommand _downloadCommand;
public ICommand DownloadCommand
{
get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download, () => IsEnabled)); }
}
private ICommand _cancelDownloadCommand;
public ICommand CancelDownloadCommand
{
get
{
return _cancelDownloadCommand ??
(_cancelDownloadCommand = new RelayCommand(CancelDownload, () => IsEnabledCancel));
}
}
private bool _isEnabled = true;
private bool IsEnabled
{
get { return _isEnabled; }
set
{
if (_isEnabled != value)
{
_isEnabled = value;
RaisePropertyChanged();
}
}
}
private bool _isEnabledCancel;
private bool IsEnabledCancel
{
get { return _isEnabledCancel; }
set
{
if (_isEnabledCancel != value)
{
_isEnabledCancel = value;
RaisePropertyChanged();
}
}
}
通过使用 CommandManager.InvalidateRequerySuggested(),我修复了它。但请阅读不推荐的地方,因为此命令会检查所有RelayCommand。这在我之前没有发生过。
但是如果在Task.Run中没有添加任何东西。它完美地运作。按钮被激活并再次停用。
private async void Download()
{
Reset();
await Task.Run(() =>
{
// WIDTHOUT CODE
// WIDTHOUT CODE
// WIDTHOUT CODE
});
Reset();
}
答案 0 :(得分:1)
当您更新CanExecute
时,在您的案例IsEnabled
和IsEnabledCancel
属性中,您必须举起CanExecuteChanged
个事件。
您可以更轻松地简化代码。
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (Set(ref _isEnabled, value))
{
DownloadCommand.RaiseCanExecuteChanged();
}
}
}
以同样的方式更新您的IsEnabledCancel
媒体资源。
当然,您必须将命令声明为RelayCommand
而不是ICommand
。
private RelayCommand _downloadCommand;
public RelayCommand DownloadCommand
{
get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download, () => IsEnabled)); }
}
您还可以阅读:&#34; A smart MVVM command&#34;。
答案 1 :(得分:1)
查看source code for MVVM Light,它基于CommandManager.InvalidateRequerySuggested()
(反)模式。由于(反)模式的全球性,你正确地说这是一场巨大的表现。
问题在于构造函数。 public RelayCommand(Action execute, Func<bool> canExecute)
如果canExecute
为Func<bool>
,则无法(在运行时)获取属性名称,因此无法绑定INotifyPropertyChanged.PropertyChanged
事件。从而导致命令重新评估canExecute
。
@kubakista向您展示如何通过调用RaiseCanExecuteChanged
方法强制重新评估。但这确实打破了单一责任原则,并泄漏了ICommand
的实施。
我的建议是使用ReactiveUI
的{{1}}。这允许你这样做:
ReactiveCommand
答案 2 :(得分:0)
我注意到的一件事是,Enabled
属性(IsEnabled,IsEnabledCancel)属private
时应为public
。但是,这不能解决您的问题:)
一个简单的解决方法是摆脱命令的CanExecute
部分
例如
public ICommand DownloadCommand
{
get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download)); }
}
并绑定到xaml中Button.IsEnabled
属性上的属性
例如
<Button IsEnabled="{Binding IsEnabled}" Margin="5" VerticalAlignment="Top"
HorizontalAlignment="Center" Command="{Binding DownloadCommand}"
FontSize="20" Background="Transparent" BorderThickness="2"
BorderBrush="Red" ToolTip="Descargar" DockPanel.Dock="Right">
...
</Button>
希望有所帮助