reactiveui / ReactiveUI

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming. ReactiveUI allows you to abstract mutable state away from your user interfaces, express the idea around a feature in one readable place and improve the testability of your application.
https://www.reactiveui.net
MIT License
8.07k stars 1.12k forks source link

[Bug]: Modifying button enabled state in a ReactiveCommand triggered by that button fails #3293

Closed philipkaare closed 2 years ago

philipkaare commented 2 years ago

Describe the bug 🐞

When connecting a button to a ReactiveCommand, which updates a variable in the ViewModel which decides button enabled state, I would expect that the enabled state of the button is updated based on that variable.

Step to reproduce

  1. Click first on "Works", the button is then disabled.
  2. Click on "Doesn't work" and the button is not disabled.

Reproduction repository

https://github.com/philipkaare/ReactiveUIWinformsBug

Expected behavior

Would expect that the enabled state is updated correctly.

Screenshots 🖼️

No response

IDE

Visual Studio 2022

Operating system

Windows

Version

11

Device

PC

ReactiveUI Version

18.1.8

Additional information ℹ️

Calling Application.DoEvents() in the ReactiveCommand solves the problem.

ChrisPulman commented 2 years ago

Hi Philip, the command runs in a task pool thread therefore the UI thread is being held until the command has completed, calling DoEvents() will invoke a refresh of the UI thread causing the update to occur. There is an overload available for the command called CanExecute this takes an Observable which allows you to control both when the command can be executed and the UI of the button will automatically disable the button when this Observable returns false. You only require a single binding for your command to the button, everything else happens magically in the background. I can provide a PR to your repo later to demonstrate the correct way.

philipkaare commented 2 years ago

Hi Chris,

Thanks for replying so quickly! I was aware of the CanExecute overload, but it was not clear to me it would influence whether the button is enabled or not. In any case, the observable is running in the UI thread as far as I can see, so I am a bit confused as to why the call to Application.DoEvents is needed? Is it because the button itself is active?

And if you have the time, I would love to see the PR :)

ChrisPulman commented 2 years ago

Please see Pull request with updated code for an updated method for your requirements.

philipkaare commented 2 years ago

Awesome! Thanks, I really appreciate it.

I have one question though; I can see that in this case there is a specific way to do it that's built in to ReactiveUI, but what if I wanted to change the color of the button or something else, that is not specifically supported?

ChrisPulman commented 2 years ago

I have updated the PR to include a colour change for the buttons

philipkaare commented 2 years ago

@ChrisPulman , thanks so much! I feel like the threading model of ReactiveUI with Winforms is a bit complicated - is there any documentation you can recommend?

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.