将可见性绑定到ReactiveCommand CanExecute

时间:2014-04-30 18:55:24

标签: wpf visibility system.reactive reactiveui canexecute

我的xaml中有几个Tiles(TileLayoutControl Class)(在此示例中仅显示2 ),其可见性绑定到布尔属性并通过BooleanToVisibilityConverter转换。
这很好用。我的问题是

我可以将可见性绑定到Command,以便我可以删除那几个布尔属性的需要吗?

将可见性绑定到 Command.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}}"/>

视图模型

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());

3 个答案:

答案 0 :(得分:5)

是的,只需使用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);

答案 1 :(得分:2)

ReactiveCommand是ICommand实施,同时是RelayCommand实施......

假设ReactiveCommand已被声明为......

public ReactiveCommand FileCommand { get; private set; }

...已经在像这样的View模型中实例化了......

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对象图中的静态资源。

注意:使用&#39;代码隐藏&#39;可以实现相同的功能。在ReactiveUI中可用,但Xaml / ValueConverter吸引那些不希望他们的View Models明确处理&#39; Visibility&#39;属性。

答案 2 :(得分:1)

您可能会这样做,但它需要对命令进行子类化,以便它也实现INotifyPropertyChanged,并且基础条件需要为PropertyChange属性提升CanExecute。变化。

如果没有,ICommand未实现INotifyPropertyChanged,它将无法使用{ - 1}}。

请注意,您可以通过在构造函数中自己处理它来简化属性:

CanExecuteChanged

然后你的财产变成:

// In constructor:
Tile1Command = new ReactiveCommand();
Tile1Command.Subscribe(p => PerformTile1Operation());

IReactiveObject self = this as IReactiveObject;

Tile1Command.CanExecuteChanged += (o,e) => self.RaisePropertyChanged(new PropertyChangedEventArgs("IsTile1Visible"));