Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Add flag to NotifyPropertyChangedFor and NotifyCanExecuteChangedFor that allows notification on sub property changes

未关闭
#1,168 1 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
冷清
技术栈
csharp

调研方向

从 NotifyPropertyChangedForAttribute 和 NotifyCanExecuteChangedForAttribute 开始,然后跟踪 ObservableProperty 和 RelayCommand 的源代码生成器入口点。将请求生成的 setter 和子属性处理程序与当前的生成输出进行比较。完成的标准是确定 API,并为子属性更改提供正常工作的通知,包括 RelayCommand 的情况。

由索引模型根据 Issue 内容生成。

描述

feature request :mailbox_with_mail:
Overview

I frequently have a property that depends on the sub-property of another property in my viewmodels. The most common case for me is the IsRunning property of AsyncRelayCommand, but I've run into many other examples.
I'd like some sort of way to indicate that another property or command has changed when a sub-property has changed. Ideally this could be extended to [RelayCommand] declarations as well so that when the automatically generated command starts or stops, other properties are notified.

API breakdown

Preferably we could add a boolean property called NotifyOnSubPropertyChanged to NotifyPropertyChangedForAttribute and NotifyCanExecuteChangedForAttribute that opts into this behavior when set to true.

Usage example

I would use it like this:

public partial class TestViewModel : ObservableObject
{
	[ObservableProperty]
	[NotifyPropertyChangedFor(nameof(FormattedProp1), NotifyOnSubPropertyChanged = true)]
	[NotifyCanExecuteChangedFor(nameof(Command1Command), NotifyOnSubPropertyChanged = true)]
	public partial SubViewModel SubViewModel { get; private set; } = new();

	public string FormattedProp1 => "_" + SubViewModel.Prop1 + "_";

	[RelayCommand(CanExecute = nameof(CanDoThing1))]
	[property: NotifyCanExecuteChangedFor(nameof(DoThing2Command), NotifyOnSubPropertyChanged = true)]
	private Task DoThing1() => Task.CompletedTask;
	private bool CanDoThing1() => SubViewModel.Prop1 is not null;

	[RelayCommand(CanExecute = nameof(CanDoThing2))]
	private void DoThing2() { }
	private bool CanDoThing2() => !DoThing1Command.IsRunning;
}

public partial class SubViewModel : ObservableObject
{
	[ObservableProperty]
	public partial string Prop1 { get; set; }
}

I think the generated code would look something like this for the SubViewModel property:

/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.4.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public partial global::WpfTests.SubViewModel SubViewModel
{
    get => field;
    private set
    {
        if (!global::System.Collections.Generic.EqualityComparer<global::WpfTests.SubViewModel>.Default.Equals(field, value))
        {
            OnSubViewModelChanging(value);
            OnSubViewModelChanging(default, value);
            OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.SubViewModel);
            OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.FormattedProp1);
            (field as INotifyPropertyChanged)?.PropertyChanged -= OnSubPropertyChanged;
            field = value;
            (field as INotifyPropertyChanged)?.PropertyChanged += OnSubPropertyChanged;
            OnSubViewModelChanged(value);
            OnSubViewModelChanged(default, value);
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.SubViewModel);
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.FormattedProp1);
            DoThing1Command.NotifyCanExecuteChanged();
        }
        
        void OnSubPropertyChanged(object? sender, PropertyChangedEventArgs args) 
        {
            OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.FormattedProp1);
            DoThing1Command.NotifyCanExecuteChanged();
        }
    }

Note that the handler for detecting sub-property changes is removed and added in the parent property setter, and the handler itself is a local function of the setter that is populated based on the property names provided.

I'm not sure how it would integrate into the RelayCommandAttribute, but it would be really nice to have for that for asynchronous commands.

Breaking change?

No

Alternatives

Right now all of this has to be configured in the constructor or initializer, and greatly hinders some of the benefits of the source generators.

An alternative might be to have a new attribute, but I think this is a little cleaner.

Additional context

No response

Help us help you

Yes, but only if others can assist

主要语言
C#
星标
3.8k
派生
403
PR 合并指标
30 天内没有已合并 PR

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

CommunityToolkit/dotnet 的其他 Issue

查看 CommunityToolkit/dotnet 的全部 Issue

相似的 Issue

更多 C# Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。