我的xaml中有几个Tile(TileLayoutControl类((在本例中只显示了2个(,它们的Visibility绑定到布尔属性并通过BooleanToVisibilityConverter进行转换
这很好用。我的问题是
我可以将可见性绑定到命令吗?这样我就可以消除对这几个布尔属性的需要吗
类似于将Visibility绑定到命令。CanExecute
如果是,我该如何实现?任何帮助都将不胜感激!谢谢
<dxlc:Tile Command="{Binding Tile1Command}"
Visibility="{Binding Path=IsTile1Visible , Converter={StaticResource BooleanToVisibilityConverter}}"/>
<dxlc:Tile Command="{Binding Tile2Command}"
Visibility="{Binding Path=IsTile2Visible , Converter={StaticResource BooleanToVisibilityConverter}}"/>
ViewModel
private bool _isTile1Visible;
public bool IsTile1Visible
{
get { return _isTile1Visible; }
set { this.RaiseAndSetIfChanged(ref _isTile1Visible, value); }
}
public ReactiveCommand Tile1Command { get; private set; }
Tile1Command = new ReactiveCommand();
Tile1Command.Subscribe(p => PerformTile1Operation());
是的,只需使用RxUI绑定:
<dxlc:Tile x:Name="Tile1" />
然后在您的View构造函数中(确保实现IViewFor<Tile1ViewModel>
以获得此扩展(:
this.BindCommand(ViewModel, x => x.Tile1Command);
this.WhenAnyObservable(x => x.ViewModel.Tile1Command.CanExecuteObservable)
.BindTo(this, x => x.Tile1.Visibility);
你也可以在ViewModel级别解决这个问题,尽管我不会这么做——在ViewModel ctor:中
Tile1Command = new ReactiveCommand(/* ... */);
Tile1Command
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.ToProperty(this, x => x.Tile1Visibility, out tile1Visibility);
ReactiveCommand是ICommand
实现,同时也是RelayCommand
实现。。。
假设ReactiveCommand是这样声明的。。。
public ReactiveCommand FileCommand { get; private set; }
并且已经在这样的视图模型中实例化。。。
SomeText = "";
FileCommand = new ReactiveCommand(this.WhenAny(vm => vm.SomeText, s => !string.IsNullOrWhiteSpace(s.Value)));
FileCommand.Subscribe(param => MessageBox.Show("Processing"));
这意味着如果属性SomeText为空,则无法执行该命令,否则可以执行该命令。如果执行该命令,将显示一个消息框。
如果您的目标是简单地消除布尔IsTile1Visible
,那么您可以做出这样的Xaml声明。。。
<Button Content="File"
Command="{Binding FileCommand}"
Visibility="{Binding FileCommand, Converter={genericMvvm1:CommandToVisibilityConverter}}" />
其中可见性绑定到同一命令并使用值转换器。。。
值转换器看起来是这样的。。。
public class CommandToVisibilityConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
ICommand iCommand = value as ICommand;
if (iCommand != null)
{
if (iCommand.CanExecute(parameter))
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
}
catch
{
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
值转换器只是将命令取消引用到一个基本的ICommand中,并将其转换为可见性。请注意,由于此转换器继承自Markup Extension
,因此无需在Xaml的对象图中将其声明为静态资源。
注意:使用ReactiveUI中的"代码隐藏"可以实现相同的功能,但Xaml/ValueConverter吸引了那些不希望视图模型显式处理"可见性"属性的开发人员。
您可能会这样做,但这需要将命令子类化,以便它也实现INotifyPropertyChanged
,并且无论何时CanExecute
属性发生更改,底层条件都需要为其引发PropertyChange
。
没有它就无法工作,因为ICommand
没有实现INotifyPropertyChanged
,而是使用CanExecuteChanged
。
请注意,您可以通过在构造函数中自己处理属性来简化属性:
// In constructor:
Tile1Command = new ReactiveCommand();
Tile1Command.Subscribe(p => PerformTile1Operation());
IReactiveObject self = this as IReactiveObject;
Tile1Command.CanExecuteChanged += (o,e) => self.RaisePropertyChanged(new PropertyChangedEventArgs("IsTile1Visible"));
然后您的财产变成:
// Use command directly here...
public bool IsTile1Visible
{
get { return Tile1Command.CanExecute; }
}