RSCG – CommunityToolkit.Mvvm
name | CommunityToolkit.Mvvm |
nuget | https://www.nuget.org/packages/CommunityToolkit.Mvvm |
link | https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/overview |
author | Microsoft |
Shows how to implement INotifyPropertyChanged,ObservableProperty and RelayCommand
Unfortunately , not yet a separate package just for those.
Also, this show that RSCG could generate multiple partial declarations
This is how you can use CommunityToolkit.Mvvm .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" /> </ItemGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> </Project>
The code that you will use is
// See https://aka.ms/new-console-template for more information using test; Console.WriteLine("Hello, World!"); MyViewModel myViewModel = new(); myViewModel.Name = "Andrei"; var x=myViewModel.SayHelloCommand;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace test; [INotifyPropertyChanged] public partial class MyViewModel { [ObservableProperty] private string? name; [RelayCommand] private void SayHello() { Console.WriteLine("Hello"); } }
The code that is generated is
// <auto-generated/> #pragma warning disable #nullable enable namespace test { /// <inheritdoc/> partial class MyViewModel : global::System.ComponentModel.INotifyPropertyChanged { /// <inheritdoc cref = "global::System.ComponentModel.INotifyPropertyChanged.PropertyChanged"/> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public event global::System.ComponentModel.PropertyChangedEventHandler? PropertyChanged; /// <summary> /// Raises the <see cref = "PropertyChanged"/> event. /// </summary> /// <param name = "e">The input <see cref = "global::System.ComponentModel.PropertyChangedEventArgs"/> instance.</param> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected virtual void OnPropertyChanged(global::System.ComponentModel.PropertyChangedEventArgs e) { PropertyChanged?.Invoke(this, e); } /// <summary> /// Raises the <see cref = "PropertyChanged"/> event. /// </summary> /// <param name = "propertyName">(optional) The name of the property that changed.</param> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected void OnPropertyChanged([global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { OnPropertyChanged(new global::System.ComponentModel.PropertyChangedEventArgs(propertyName)); } /// <summary> /// Compares the current and new values for a given property. If the value has changed, updates /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event. /// </summary> /// <typeparam name = "T">The type of the property that changed.</typeparam> /// <param name = "field">The field storing the property's value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<T>([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(field, newValue)) { return false; } field = newValue; OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given property. If the value has changed, updates /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event. /// See additional notes about this overload in <see cref = "SetProperty{T}(ref T, T, string)"/>. /// </summary> /// <typeparam name = "T">The type of the property that changed.</typeparam> /// <param name = "field">The field storing the property's value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<T>([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { if (comparer.Equals(field, newValue)) { return false; } field = newValue; OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given property. If the value has changed, updates /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event. /// This overload is much less efficient than <see cref = "SetProperty{T}(ref T, T, string)"/> and it /// should only be used when the former is not viable (eg. when the target property being /// updated does not directly expose a backing field that can be passed by reference). /// For performance reasons, it is recommended to use a stateful callback if possible through /// the <see cref = "SetProperty{TModel, T}(T, T, TModel, global::System.Action{TModel, T}, string? )"/> whenever possible /// instead of this overload, as that will allow the C# compiler to cache the input callback and /// reduce the memory allocations. More info on that overload are available in the related XML /// docs. This overload is here for completeness and in cases where that is not applicable. /// </summary> /// <typeparam name = "T">The type of the property that changed.</typeparam> /// <param name = "oldValue">The current property value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "callback">A callback to invoke to update the property value.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<T>(T oldValue, T newValue, global::System.Action<T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(oldValue, newValue)) { return false; } callback(newValue); OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given property. If the value has changed, updates /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event. /// See additional notes about this overload in <see cref = "SetProperty{T}(T, T, global::System.Action{T}, string)"/>. /// </summary> /// <typeparam name = "T">The type of the property that changed.</typeparam> /// <param name = "oldValue">The current property value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param> /// <param name = "callback">A callback to invoke to update the property value.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<T>(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, global::System.Action<T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { if (comparer.Equals(oldValue, newValue)) { return false; } callback(newValue); OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given nested property. If the value has changed, /// updates the property and then raises the <see cref = "PropertyChanged"/> event. /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, /// with the difference being that this method is used to relay properties from a wrapped model in the /// current instance. This type is useful when creating wrapping, bindable objects that operate over /// models that lack support for notification (eg. for CRUD operations). /// Suppose we have this model (eg. for a database row in a table): /// <code> /// public class Person /// { /// public string Name { get; set; } /// } /// </code> /// We can then use a property to wrap instances of this type into our observable model (which supports /// notifications), injecting the notification to the properties of that model, like so: /// <code> /// [INotifyPropertyChanged] /// public partial class BindablePerson /// { /// public Model { get; } /// /// public BindablePerson(Person model) /// { /// Model = model; /// } /// /// public string Name /// { /// get => Model.Name; /// set => Set(Model.Name, value, Model, (model, name) => model.Name = name); /// } /// } /// </code> /// This way we can then use the wrapping object in our application, and all those "proxy" properties will /// also raise notifications when changed. Note that this method is not meant to be a replacement for /// <see cref = "SetProperty{T}(ref T, T, string)"/>, and it should only be used when relaying properties to a model that /// doesn't support notifications, and only if you can't implement notifications to that model directly (eg. by having /// it implement <see cref = "global::System.ComponentModel.INotifyPropertyChanged"/>). The syntax relies on passing the target model and a stateless callback /// to allow the C# compiler to cache the function, which results in much better performance and no memory usage. /// </summary> /// <typeparam name = "TModel">The type of model whose property (or field) to set.</typeparam> /// <typeparam name = "T">The type of property (or field) to set.</typeparam> /// <param name = "oldValue">The current property value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "model">The model containing the property being updated.</param> /// <param name = "callback">The callback to invoke to set the target property value, if a change has occurred.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<TModel, T>(T oldValue, T newValue, TModel model, global::System.Action<TModel, T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) where TModel : class { if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(oldValue, newValue)) { return false; } callback(model, newValue); OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given nested property. If the value has changed, /// updates the property and then raises the <see cref = "PropertyChanged"/> event. /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, /// with the difference being that this method is used to relay properties from a wrapped model in the /// current instance. See additional notes about this overload in <see cref = "SetProperty{TModel, T}(T, T, TModel, global::System.Action{TModel, T}, string)"/>. /// </summary> /// <typeparam name = "TModel">The type of model whose property (or field) to set.</typeparam> /// <typeparam name = "T">The type of property (or field) to set.</typeparam> /// <param name = "oldValue">The current property value.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param> /// <param name = "model">The model containing the property being updated.</param> /// <param name = "callback">The callback to invoke to set the target property value, if a change has occurred.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetProperty<TModel, T>(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, TModel model, global::System.Action<TModel, T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) where TModel : class { if (comparer.Equals(oldValue, newValue)) { return false; } callback(model, newValue); OnPropertyChanged(propertyName); return true; } /// <summary> /// Compares the current and new values for a given field (which should be the backing field for a property). /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event. /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, with the difference being that /// this method will also monitor the new value of the property (a generic <see cref = "global::System.Threading.Tasks.Task"/>) and will also /// raise the <see cref = "PropertyChanged"/> again for the target property when it completes. /// This can be used to update bindings observing that <see cref = "global::System.Threading.Tasks.Task"/> or any of its properties. /// This method and its overload specifically rely on the <see cref = "TaskNotifier"/> type, which needs /// to be used in the backing field for the target <see cref = "global::System.Threading.Tasks.Task"/> property. The field doesn't need to be /// initialized, as this method will take care of doing that automatically. The <see cref = "TaskNotifier"/> /// type also includes an implicit operator, so it can be assigned to any <see cref = "global::System.Threading.Tasks.Task"/> instance directly. /// Here is a sample property declaration using this method: /// <code> /// private TaskNotifier myTask; /// /// public Task MyTask /// { /// get => myTask; /// private set => SetAndNotifyOnCompletion(ref myTask, value); /// } /// </code> /// </summary> /// <param name = "taskNotifier">The field notifier to modify.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are /// the same. The return value being <see langword="true"/> only indicates that the new value being assigned to /// <paramref name = "taskNotifier"/> is different than the previous one, and it does not mean the new /// <see cref = "global::System.Threading.Tasks.Task"/> instance passed as argument is in any particular state. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetPropertyAndNotifyOnCompletion([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier? taskNotifier, global::System.Threading.Tasks.Task? newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, null, propertyName); } /// <summary> /// Compares the current and new values for a given field (which should be the backing field for a property). /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event. /// This method is just like <see cref = "SetPropertyAndNotifyOnCompletion(ref TaskNotifier, global::System.Threading.Tasks.Task, string)"/>, /// with the difference being an extra <see cref = "global::System.Action{T}"/> parameter with a callback being invoked /// either immediately, if the new task has already completed or is <see langword="null"/>, or upon completion. /// </summary> /// <param name = "taskNotifier">The field notifier to modify.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "callback">A callback to invoke to update the property value.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetPropertyAndNotifyOnCompletion([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier? taskNotifier, global::System.Threading.Tasks.Task? newValue, global::System.Action<global::System.Threading.Tasks.Task?> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, callback, propertyName); } /// <summary> /// Compares the current and new values for a given field (which should be the backing field for a property). /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event. /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, with the difference being that /// this method will also monitor the new value of the property (a generic <see cref = "global::System.Threading.Tasks.Task"/>) and will also /// raise the <see cref = "PropertyChanged"/> again for the target property when it completes. /// This can be used to update bindings observing that <see cref = "global::System.Threading.Tasks.Task"/> or any of its properties. /// This method and its overload specifically rely on the <see cref = "TaskNotifier{T}"/> type, which needs /// to be used in the backing field for the target <see cref = "global::System.Threading.Tasks.Task"/> property. The field doesn't need to be /// initialized, as this method will take care of doing that automatically. The <see cref = "TaskNotifier{T}"/> /// type also includes an implicit operator, so it can be assigned to any <see cref = "global::System.Threading.Tasks.Task"/> instance directly. /// Here is a sample property declaration using this method: /// <code> /// private TaskNotifier<int> myTask; /// /// public Task<int> MyTask /// { /// get => myTask; /// private set => SetAndNotifyOnCompletion(ref myTask, value); /// } /// </code> /// </summary> /// <typeparam name = "T">The type of result for the <see cref = "global::System.Threading.Tasks.Task{TResult}"/> to set and monitor.</typeparam> /// <param name = "taskNotifier">The field notifier to modify.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are /// the same. The return value being <see langword="true"/> only indicates that the new value being assigned to /// <paramref name = "taskNotifier"/> is different than the previous one, and it does not mean the new /// <see cref = "global::System.Threading.Tasks.Task{TResult}"/> instance passed as argument is in any particular state. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetPropertyAndNotifyOnCompletion<T>([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier<T>? taskNotifier, global::System.Threading.Tasks.Task<T>? newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, null, propertyName); } /// <summary> /// Compares the current and new values for a given field (which should be the backing field for a property). /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event. /// This method is just like <see cref = "SetPropertyAndNotifyOnCompletion{T}(ref TaskNotifier{T}, global::System.Threading.Tasks.Task{T}, string)"/>, /// with the difference being an extra <see cref = "global::System.Action{T}"/> parameter with a callback being invoked /// either immediately, if the new task has already completed or is <see langword="null"/>, or upon completion. /// </summary> /// <typeparam name = "T">The type of result for the <see cref = "global::System.Threading.Tasks.Task{TResult}"/> to set and monitor.</typeparam> /// <param name = "taskNotifier">The field notifier to modify.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "callback">A callback to invoke to update the property value.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> /// <remarks> /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same. /// </remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected bool SetPropertyAndNotifyOnCompletion<T>([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier<T>? taskNotifier, global::System.Threading.Tasks.Task<T>? newValue, global::System.Action<global::System.Threading.Tasks.Task<T>?> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) { return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, callback, propertyName); } /// <summary> /// Implements the notification logic for the related methods. /// </summary> /// <typeparam name = "TTask">The type of <see cref = "global::System.Threading.Tasks.Task"/> to set and monitor.</typeparam> /// <param name = "taskNotifier">The field notifier.</param> /// <param name = "newValue">The property's value after the change occurred.</param> /// <param name = "callback">(optional) A callback to invoke to update the property value.</param> /// <param name = "propertyName">(optional) The name of the property that changed.</param> /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] private bool SetPropertyAndNotifyOnCompletion<TTask>(ITaskNotifier<TTask> taskNotifier, TTask? newValue, global::System.Action<TTask?>? callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null) where TTask : global::System.Threading.Tasks.Task { if (ReferenceEquals(taskNotifier.Task, newValue)) { return false; } bool isAlreadyCompletedOrNull = newValue?.IsCompleted ?? true; taskNotifier.Task = newValue; OnPropertyChanged(propertyName); if (isAlreadyCompletedOrNull) { if (callback != null) { callback(newValue); } return true; } async void MonitorTask() { await global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__TaskExtensions.GetAwaitableWithoutEndValidation(newValue!); if (ReferenceEquals(taskNotifier.Task, newValue)) { OnPropertyChanged(propertyName); } if (callback != null) { callback(newValue); } } MonitorTask(); return true; } /// <summary> /// An interface for task notifiers of a specified type. /// </summary> /// <typeparam name = "TTask">The type of value to store.</typeparam> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] private interface ITaskNotifier<TTask> where TTask : global::System.Threading.Tasks.Task { /// <summary> /// Gets or sets the wrapped <typeparamref name = "TTask"/> value. /// </summary> TTask? Task { get; set; } } /// <summary> /// A wrapping class that can hold a <see cref = "global::System.Threading.Tasks.Task"/> value. /// </summary> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected sealed class TaskNotifier : ITaskNotifier<global::System.Threading.Tasks.Task> { /// <summary> /// Initializes a new instance of the <see cref = "TaskNotifier"/> class. /// </summary> internal TaskNotifier() { } private global::System.Threading.Tasks.Task? task; /// <inheritdoc/> global::System.Threading.Tasks.Task? ITaskNotifier<global::System.Threading.Tasks.Task>.Task { get => this.task; set => this.task = value; } /// <summary> /// Unwraps the <see cref = "global::System.Threading.Tasks.Task"/> value stored in the current instance. /// </summary> /// <param name = "notifier">The input <see cref = "TaskNotifier{TTask}"/> instance.</param> public static implicit operator global::System.Threading.Tasks.Task? (TaskNotifier? notifier) { return notifier?.task; } } /// <summary> /// A wrapping class that can hold a <see cref = "global::System.Threading.Tasks.Task{T}"/> value. /// </summary> /// <typeparam name = "T">The type of value for the wrapped <see cref = "global::System.Threading.Tasks.Task{T}"/> instance.</typeparam> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] protected sealed class TaskNotifier<T> : ITaskNotifier<global::System.Threading.Tasks.Task<T>> { /// <summary> /// Initializes a new instance of the <see cref = "TaskNotifier{TTask}"/> class. /// </summary> internal TaskNotifier() { } private global::System.Threading.Tasks.Task<T>? task; /// <inheritdoc/> global::System.Threading.Tasks.Task<T>? ITaskNotifier<global::System.Threading.Tasks.Task<T>>.Task { get => this.task; set => this.task = value; } /// <summary> /// Unwraps the <see cref = "global::System.Threading.Tasks.Task{T}"/> value stored in the current instance. /// </summary> /// <param name = "notifier">The input <see cref = "TaskNotifier{TTask}"/> instance.</param> public static implicit operator global::System.Threading.Tasks.Task<T>? (TaskNotifier<T>? notifier) { return notifier?.task; } } } }
// <auto-generated/> #pragma warning disable #nullable enable namespace test { /// <inheritdoc/> partial class MyViewModel { /// <inheritdoc cref="name"/> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public string? Name { get => name; set { if (!global::System.Collections.Generic.EqualityComparer<string?>.Default.Equals(name, value)) { OnNameChanging(value); OnNameChanging(default, value); name = value; OnNameChanged(value); OnNameChanged(default, value); OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name); } } } /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary> /// <param name="value">The new property value being set.</param> /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] partial void OnNameChanging(string? value); /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary> /// <param name="oldValue">The previous property value that is being replaced.</param> /// <param name="newValue">The new property value being set.</param> /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] partial void OnNameChanging(string? oldValue, string? newValue); /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary> /// <param name="value">The new property value that was set.</param> /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] partial void OnNameChanged(string? value); /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary> /// <param name="oldValue">The previous property value that was replaced.</param> /// <param name="newValue">The new property value that was set.</param> /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] partial void OnNameChanged(string? oldValue, string? newValue); } }
// <auto-generated/> #pragma warning disable #nullable enable namespace CommunityToolkit.Mvvm.ComponentModel.__Internals { /// <summary> /// A helper type providing cached, reusable <see cref="global::System.ComponentModel.PropertyChangedEventArgs"/> instances /// for all properties generated with <see cref="global::CommunityToolkit.Mvvm.ComponentModel.ObservablePropertyAttribute"/>. /// </summary> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")] [global::System.Diagnostics.DebuggerNonUserCode] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] [global::System.Obsolete("This type is not intended to be used directly by user code")] internal static class __KnownINotifyPropertyChangedArgs { /// <summary>The cached <see cref="global::System.ComponentModel.PropertyChangedEventArgs"/> instance for all "Name" generated properties.</summary> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] [global::System.Obsolete("This field is not intended to be referenced directly by user code")] public static readonly global::System.ComponentModel.PropertyChangedEventArgs Name = new global::System.ComponentModel.PropertyChangedEventArgs("Name"); } }
// <auto-generated/> #pragma warning disable #nullable enable namespace test { /// <inheritdoc/> partial class MyViewModel { /// <summary>The backing field for <see cref="SayHelloCommand"/>.</summary> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.2.0.0")] private global::CommunityToolkit.Mvvm.Input.RelayCommand? sayHelloCommand; /// <summary>Gets an <see cref="global::CommunityToolkit.Mvvm.Input.IRelayCommand"/> instance wrapping <see cref="SayHello"/>.</summary> [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.2.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public global::CommunityToolkit.Mvvm.Input.IRelayCommand SayHelloCommand => sayHelloCommand ??= new global::CommunityToolkit.Mvvm.Input.RelayCommand(new global::System.Action(SayHello)); } }
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/CommunityToolkit.Mvvm
Leave a Reply