The order of 'IsEnabled' and 'Command' should not matter #2758
Comments
I just checked with native UWP, and the matrix is the platform does - and the order doesn't matter. |
@pauldipietro I don't think is is a XAML issue. IsEnabledProperty and Command.CanExecute are each changing IsEnabled completely independent of one another. You could fail the matrix above with pure C#. |
I was looking at this and I think the real issue is the fact that the IsEnabled property is being overwritten entirely. class VisualElement {
BindableProperty IsEnabledProperty = BindableProperty.Create(
...,
coerceValue: OnIsEnabledCoerce);
static object OnIsEnabledCoerce(BindableObject bindable, object value) {
var element = (VisualElement)bindable;
if (element == null)
return false;
if ((bool)value) {
return element.IsEnabledCore;
} else {
return false;
}
}
protected virtual bool IsEnabledCore { get { return true; } }
}
class Button {
protected override bool IsEnabledCore {
get { return base.IsEnabledCore && CanExecute; }
}
bool CanExecute {
get { return _canExecute; }
set {
if (_canExecute != value) {
_canExecute = value;
ReCoerceValue(IsEnabledProperty);
}
}
}
void CommandCanExecuteChanged(object sender, EventArgs eventArgs) {
CanExecute = Command?.CanExecute(CommandParameter) ?? true;
}
} |
I tried to do something, but the binding code is just a bit too complex for me at the moment. I could get things to work mostly OK if I stored the RealValue, the CoercedValue and a IsCoerced flag, but things got wonky because I don't quite understand the setting logic too well. Hopefully this helps someone, somewhere. |
unrelated to xaml, the same can be achieved in code |
It used to matter what order you have. Currently it looks like it's broken all the way. IsEnabled works until I add Command. As soon as I do that, it doesn't look at IsEnabled anymore. |
This problem is many years old, I think at least 3. @StephaneDelcroix Shouldn't this be marked as a bug and not as an enhancement? |
From all the XAML frameworks, this problem is only in Xamarin Forms |
perhaps leave it to me to ruin the party here... but this would introduce a MAJOR breaking change in behavior which means you break people without them knowing it... now "Maybe" its a worthwhile break (though I heavily lean towards no)... but can you honestly name a scenario in which you have two buttons attached to the same command where one should be disabled and the other shouldn't... and you're either NOT using a Parameter or using the same Command Parameter? The entire point of Can Execute is that you're evaluating the parameter null or otherwise to determine if it can/should execute... |
This certainly seems like a bug to me... If it cannot be fixed, I would at least propose some sort of warning be added to the documentation of the IsEnabled property and the Button class. I've created a small project to reproduce the issue, as well as provided a few branches to demonstrate ways to avoid the issue by using CanExecute rather than IsEnabled: https://github.com/jbachelor/XamarinFormsIsEnabledIssue |
Issues like this exist in other places too. I remember looking at the min/max values for Slider a long time ago. Validation/coercing happens at the property level so the order of things being set matters. I agree that any fix here will introduce a breaking change. Right now, documentation seems to be the way to go. |
It didn't work for me regardless of order. I solved the problem by putting the button in a stacklayout and setting IsEnabled on that, and also setting BackgroundColor on the button from my behaviour so that the disabled state showed properly on the button. |
I confirm its still an issue , its taking order into action
I dont know the implications of not setting Command.ChangeCanExecute to Button IsEnabled property internally in Xamarin, as a developer I certainly wont call Command.ChaneCanExecute everytime I want to disable button. If that is what expected then I can understand. |
Guy, there is an easy fix for this. IsEnable property is only bound to Clicked event. With command it wont work. So the fix is MyPage.xaml MyPage.xaml.cs |
Although I agree with @dansiegel on the breaking change, I think we also need to consider how styles and state management works. For example, I could have a submit button that sends a message. But, I then have a style that overrides everything and marks the button as disabled. I do not think that these are mutually exclusive at all. The In defense of this "bug", the |
I just tested this on my own project with the last version, 4.8.0.1451, and seems to be fixed. The last version I knew it was working was 3.3 |
Using XF 5.0 error still there, you cant get IsEnable working if you have command Not Working <Button Text="Accept offer" Command="{Binding BindingContext.AcceptCommand, Source={x:Reference MyDescriptionPageName}}" CommandParameter="{Binding Id}" IsEnabled="False"/> Not Working <Button Text="Accept offer" IsEnabled="False" Command="{Binding BindingContext.AcceptCommand, Source={x:Reference MyDescriptionPageName}}" CommandParameter="{Binding Id}" /> obs: MyDescriptionPageName is just my page x:Name to be able to send Parameter public ICommand AcceptCommand=> new Command<Guid>(async (Id) => await AcceptJob(Id)); |
I have the same problem with XF5 today.
I have this stacklayout with a login and logout button. in login button, IsLoggedIn works fine. To have IsLoggedIn working also with logout button, I have used this workaround in LogoutCommand
|
I have undertand the problem
In LogoutCommand, if I set IsLoggedIn to false and allowsMultipleExecutions is set to false, the button does not disable... |
This still happens in MAUI 6.0.312 |
Like @aschuhardt mentioned, still happens with MAUI indeed, at least on Android. If it wasn't for a comment in Stack Overflow, I'd never have this figured out... |
This still occurs in MAUI, and only when I send the version with Release Mode (for testers) in develop or Debug mode not occurs, I set correctly the command and the property for canExecute command and enable/disabled the button automatically, but... the style no changed, only the button can pressed but style is disabled always... It is desperate and is something that should be corrected, at least using only the command. |
Description
I have two buttons:
For some reason, the
IsEnabled
property is overwritten in Button2 - this enables the button incorrectly.Button1 is disabled this way, but when I trigger
TheCommand.ChangeCanExecute()
, the button enables.Expected Behavior
Both buttons stay disabled.
The matrix of this should be an
&&
operation:Actual Behavior
The button with the command applied later overwrites the enabled state.
Basic Information
The text was updated successfully, but these errors were encountered: