4

我的 xaml 中有几个 Tiles(TileLayoutControl 类)(此示例中仅显示 2 个),其 Visibility 绑定到 Boolean Properties 并通过 BooleanToVisibilityConverter 进行转换。
这工作得很好。我的问题是

我可以将可见性绑定到命令,以便我可以消除对这几个布尔属性的需要吗?

类似于将 Visibility 绑定到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());
4

3 回答 3

6

是的,只需使用 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);
于 2014-05-01T04:57:35.803 回答
2

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 为空,则无法执行命令,否则可以执行命令。如果执行该命令,将显示一个消息框。

如果您的目标是简单地消除 boolean 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 吸引了不希望其视图模型显式处理“可见性”属性的开发人员。

于 2014-04-30T19:20:28.570 回答
1

您可能会这样做,但它需要对命令进行子类化,以便它也实现,并且每当属性更改时,INotifyPropertyChanged基础条件都需要引发PropertyChangeCanExecute

没有它,它就无法工作,因为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; }
}
于 2014-04-30T19:07:38.430 回答