Search code examples
c#wpfreactiveuimultidatatrigger

RxUI - WPF - Style DataTrigger binding with no DataContext


Caveat:
Brand new to ReactiveUI. Trying to go full on RxUI with the intention of never setting a view's DataContext. I believe this can be done!

Scenario:
I have a button and the button has a style and that button's style has a MultiDataTrigger with first condition being IsMouseOver and second condition being a property on my ViewModel of type bool. This then changes the background or foreground of the button. Traditionally, you would just bind that second condition to the ViewModel's property.

Is there a feasible way for this interaction to work without using a DataContext yet still have the same outcome I expect? I can't directly access the condition binding since it doesn't have a name. So there has to be some weird setup to get this to work.

Solution not really a fan of:
I could potentially add a control that isn't visible, give it a name, and use the this.OneWayBind() to bind that property to the "IsEnabled" property of this control. In doing so, my second condition of the button's MultiDataTrigger could then use binding based on ElementName and its path of IsEnabled. This would allow me to NOT use a DataContext but seems way too "hacky" for my taste. There's gotta be another way!

Thanks in advance!

Edit 1 - Attempt 1 based off Glenn Watson's comment to the post

        this.WhenActivated(disposables =>
        {
            this.WhenAnyValue(x => x.TheButton.IsMouseOver, x => x.ViewModel.SomeBoolValue).Subscribe(x =>
            {
                if (!x.Item1)
                    TheButton.Background = x.Item2 ? Brushes.Gray : Brushes.Blue;
                else
                    TheButton.Background = x.Item2 ? Brushes.Red : Brushes.Green;
            }).DisposeWith(disposables);
        });

Edit 2 - implemented/using Glenn Watson's answer.


Solution

  • I would recommend something close to the solution you have:

    this.WhenAnyValue(x => x.TheButton.IsMouseOver, x => x.ViewModel.SomeBoolValue,
          (isMouseOver, boolValue) => 
          {
             if (isMouseOver)
               return boolValue ? Brushes.Gray : Brushes.Blue;
             else 
               return boolValue ? Brushes.Red : Brushes.Green;
          })
          .BindTo(this, view => view.TheButton.Background)
          .DisposeWith(disposables);
    

    The modifications are using the third parameter which takes in a parameterized lambda to the previous two values, then just using BindTo(). It shouldn't be that dissimilar to what you've got.