2014-04-30 5 views
2

У меня есть несколько плиток (TileLayoutControl Class) в моем XAML (показаны только 2 в этом примере), чья Видимость являются переплетены в булевых свойства и преобразуется через BooleanToVisibilityConverter.
Это работает отлично. Мой вопрос:Bind Видимости в ReactiveCommand CanExecute

Могу ли я привязать видимость к команде, чтобы я мог удалить необходимость этих нескольких логических свойств?

Нечто подобное связывание видимости с 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}}"/> 

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

ответ

1

Вы могли бы потенциально сделать это, но это потребовало бы подклассов команду так, что она также реализует INotifyPropertyChanged, и основное условие будет необходимо поднять PropertyChange для CanExecute собственности, когда это изменения.

Это не сработает без этого, так как 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; } 
} 
+0

Существует много более простые способы сделать это, см. мой ответ –

+0

@PaulBetts Полезно знать - похоже, вы создали много интересных функций вокруг этих типов требований. –

2

ReactiveCommand является ICommand реализация, которая одновременно a 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; 
    } 
} 

преобразователь значений просто разыменовывает команду в основной ICom и преобразует его в видимость.Обратите внимание: поскольку этот конвертор наследует от Markup Extension, нет необходимости объявлять его как статический ресурс в графе объектов Xaml.

ПРИМЕЧАНИЕ. Та же функциональность может быть достигнута с использованием «кода-сзади», доступного в ReactiveUI, но Xaml/ValueConverter обращается к разработчикам, которые не хотят, чтобы их модели просмотра явно работали с свойством «Видимость».

+0

Код добавлен, чтобы показать декларацию ReactiveUI для команды ... –

+0

Это, безусловно, работает (т. Е. Не подводит), но это не правильный способ делать вещи - SO - источник * Документации *, я хочу, чтобы люди знали как правильно все делать с ReactiveUI. –

+0

@PaulBetts, можете ли вы пояснить, что вы подразумеваете под «Правильным способом делать что-то»? –

4

Да, просто использовать 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); 
+0

Я думаю, что «не то, что я буду делать» относится к тому, нравится ли вам писать код (для привязки) в представлении - концептуально я предпочитаю привязывать к разметке, но потом, возможно, мне нужно узнать больше новых трюков – Murph

+1

Я работал что меня беспокоит, одна из приятных вещей о привязках в разметке заключается в том, что вам не нужно указывать имена элементов XAML. Цвет меня странный, но я думаю, что это хорошо. – Murph

Смежные вопросы