RelayCommand<T>.CanExecute(null) returns false for value types without a predicate
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 84/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- csharp
- Domain
- developer-experience
Research direction
Start with src/CommunityToolkit.Mvvm/Input/RelayCommand{T}.cs and inspect the null-parameter guard and the optional canExecute predicate. Verify the repro through ICommand.CanExecute(null), then confirm that predicate-free value-type commands return true while commands with predicates retain the documented false behavior.
Written by the indexing model from the issue text.
Description
Describe the bug
RelayCommand<T>.CanExecute(object?) unconditionally returns false when T is a non-nullable value type (e.g. int, enums) and the parameter is null — even when no canExecute predicate was provided to the constructor.
This violates the documented contract: "The default return value for the CanExecute method is true." A command constructed without a predicate is meant to always be executable, regardless of the parameter value — including null.
In WPF applications on .NET Framework, the framework may call CanExecute(null) during control initialization before the CommandParameter binding has produced a value. With the unconditional return false, commands without predicates (e.g. RelayCommand<SomeEnum>(DoSomething)) are permanently disabled.
Current code (src/CommunityToolkit.Mvvm/Input/RelayCommand{T}.cs):
if (parameter is null && default(T) is not null)
{
return false; // unconditional — even when no predicate exists
}
Regression
No response
Steps to reproduce
// 1. Create a RelayCommand without a predicate
var command = new RelayCommand<int>(i => Console.WriteLine(i));
// 2. Call CanExecute with null (as WPF does during initialization)
bool result = ((System.Windows.Input.ICommand)command).CanExecute(null);
// 3. Observe the result
Console.WriteLine(result); // Actual: False, Expected: True
Expected behavior
CanExecute(null) should return true when no canExecute predicate was provided, because:
- The class documentation states the default return value is
true - Without a predicate, the command has no condition to evaluate — it should always be executable
- The
nullguard's purpose is to prevent anullfrom being incorrectly mapped todefault(T)(e.g., 0 as SelectedIndex), but when there's no predicate, there's nothing to incorrectly map to
For commands with a predicate, returning false is correct — we cannot guess the user's intent. This proposal keeps that behavior unchanged.
Screenshots
No response
IDE and version
Other
IDE version
Insiders [12020.428]
Nuget packages
- CommunityToolkit.Common
- CommunityToolkit.Diagnostics
- CommunityToolkit.HighPerformance
- CommunityToolkit.Mvvm (aka MVVM Toolkit)
Nuget package version(s)
latest stable
Additional context
- Related discussion: WindowsCommunityToolkit #3619. That issue correctly identified that mapping
nulltodefault(T)for commands with predicates is unsafe. However, the resulting unconditionalreturn falseis overly broad — it also disables commands without predicates, which have no such ambiguity. - The proposed fix is a one-line change:
return false;→return this.canExecute is null; TryGetCommandArgument、ThrowArgumentExceptionForInvalidCommandArgument、Execute(object?)remain unchanged.
Help us help you
Yes, I'd like to be assigned to work on this item
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 400
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from CommunityToolkit/dotnet
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
CommunityToolkit/dotnet#1186 ·
-
bug :bug:
Difficulty 1/5 Under an hour Newbie friendliness 68/100
CommunityToolkit/dotnet#648 ·
-
bug :bug:
Difficulty 4/5 3-5 days Newbie friendliness 58/100
CommunityToolkit/dotnet#1208 ·
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
CommunityToolkit/dotnet#1205 ·
-
feature request :mailbox_with_mail:
Difficulty 5/5 Over a week Newbie friendliness 35/100
CommunityToolkit/dotnet#1203 · 1 reaction ·
All issues in CommunityToolkit/dotnet
Similar issues
-
type/automation type/tech-debt
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
t/bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
ci-failure-cause test-failure
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
area:auth FE mvp P3
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
klasolsson81/jobbliggaren#1788 ·