diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/FrameworkTests/FrameworkTests.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/FrameworkTests/FrameworkTests.csproj
index 332542f..5439fb4 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/FrameworkTests/FrameworkTests.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/FrameworkTests/FrameworkTests.csproj
@@ -20,15 +20,17 @@
full
false
bin\Debug\
- DEBUG;TRACE
+ DEBUG;TRACE;FRAMEWORK
prompt
4
+ true
+
pdbonly
true
bin\Release\
- TRACE
+ TRACE;FRAMEWORK
prompt
4
@@ -48,6 +50,9 @@
+
+ 7.1.2
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/NetCoreTests/NetCoreTests.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/NetCoreTests/NetCoreTests.csproj
index 0473d86..853c5a6 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/NetCoreTests/NetCoreTests.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/NetCoreTests/NetCoreTests.csproj
@@ -6,7 +6,7 @@
DevExpress.Mvvm.CodeGenerators.NetCoreTests
9
true
- 8618,8604
+ True
true
@@ -15,6 +15,7 @@
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/AttributeTransferTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/AttributeTransferTests.cs
index 4639622..4baf315 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/AttributeTransferTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/AttributeTransferTests.cs
@@ -31,13 +31,13 @@ partial class AttributeTransfer {
[TestFixture]
public class AttributeTransferTests {
[Test]
- public void AttributeTransfer() {
- var noAttributeProperty = typeof(AttributeTransfer).GetProperty("NoAttribute");
+ public void AttributeTransferTest() {
+ var noAttributeProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.NoAttribute));
var attributes = Attribute.GetCustomAttributes(noAttributeProperty);
var expectedAttributes = new Attribute[] { };
Assert.AreEqual(expectedAttributes, attributes);
- var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty("WithMultipleAttributes");
+ var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.WithMultipleAttributes));
attributes = Attribute.GetCustomAttributes(withMultipleAttributesProperty);
expectedAttributes = new Attribute[] {
new System.ComponentModel.DataAnnotations.RangeAttribute(0, 1),
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/NullableAnnotationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/NullableAnnotationTests.cs
index 1b5d311..f8eee9d 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/NullableAnnotationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/NullableAnnotationTests.cs
@@ -36,6 +36,7 @@ void NonNullableParameter1(string str) { }
int? nullableInt2;
[GenerateProperty]
string string2;
+#pragma warning disable 8632
[GenerateProperty]
string? nullableString2;
@@ -48,6 +49,7 @@ void NonNullableParameter2(string str) { }
[GenerateCommand]
Task NonNullableParameterAsync2(string str) => Task.CompletedTask;
- void OnString1Changed(string str) { }
+ void OnString1Changed(string str) { }
+#pragma warning restore 8632
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/PropertyGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/PropertyGenerationTests.cs
index 65c3a36..016495e 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/PropertyGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/PropertyGenerationTests.cs
@@ -26,7 +26,7 @@ partial class WithTwoMvvmAttribute {
[Prism.GenerateProperty]
int prismProperty;
[Prism.GenerateCommand]
- void PrismMethod() { }
+ void PrismMethod() { prismProperty++; }
}
[TestFixture]
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/UsingRaiseMethodTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/UsingRaiseMethodTests.cs
index b5200d7..ed52c5a 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/UsingRaiseMethodTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/UsingRaiseMethodTests.cs
@@ -20,6 +20,11 @@ partial class ChildWithParentsGeneratedRaiseMethod : ParentWithGeneraetedRaiseMe
class ParentWithoutRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
+ public ParentWithoutRaiseMethod() {
+ //avoid warnings
+ PropertyChanged?.Invoke(null, null);
+ PropertyChanging?.Invoke(null, null);
+ }
}
[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
partial class ChildWithoutRaiseMethod : ParentWithoutRaiseMethod {
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/Helper.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/Helper.cs
similarity index 100%
rename from DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/DxTest/Helper.cs
rename to DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/Helper.cs
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/AttributeTransferTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/AttributeTransferTests.cs
index 6489a75..65df1f8 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/AttributeTransferTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/AttributeTransferTests.cs
@@ -32,13 +32,13 @@ partial class AttributeTransfer {
[TestFixture]
public class AttributeTransferTests {
[Test]
- public void AttributeTransfer() {
- var noAttributeProperty = typeof(AttributeTransfer).GetProperty("NoAttribute");
+ public void AttributeTransferTest() {
+ var noAttributeProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.NoAttribute));
var attributes = Attribute.GetCustomAttributes(noAttributeProperty);
var expectedAttributes = new Attribute[] { };
Assert.AreEqual(expectedAttributes, attributes);
- var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty("WithMultipleAttributes");
+ var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.WithMultipleAttributes));
attributes = Attribute.GetCustomAttributes(withMultipleAttributesProperty);
expectedAttributes = new Attribute[] {
new System.ComponentModel.DataAnnotations.RangeAttribute(0, 1),
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/Helper.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/Helper.cs
deleted file mode 100644
index 3d7cc78..0000000
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/Helper.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using NUnit.Framework;
-using System;
-using System.ComponentModel;
-using DevExpress.Mvvm.CodeGenerators.MvvmLight;
-
-namespace MvvmLight.Mvvm.Tests {
- static class DoWith {
- static void EventCore(
- TSender sender,
- Action action,
- Action eventAction,
- Func, THandler> subscribe,
- Action unsubscribe,
- int expectedFireCount = 1)
- where TArgs : EventArgs {
-
- var fireCount = 0;
- EventHandler handler = (o, e) => {
- Assert.AreSame(o, sender);
- eventAction(e);
- fireCount++;
- };
-
- var h = subscribe(sender, handler);
- try {
- action();
- } finally {
- unsubscribe(sender, h);
- }
- Assert.AreEqual(expectedFireCount, fireCount);
- }
-
- public static void PropertyChangedEvent(INotifyPropertyChanged inpc, Action action, Action eventAction, int fireCount = 1) {
- EventCore(
- inpc,
- action,
- eventAction,
- (o, handler) => {
- PropertyChangedEventHandler x = (sender, args) => handler(sender, args);
- inpc.PropertyChanged += x;
- return x;
- },
- (o, handler) => inpc.PropertyChanged -= handler,
- fireCount
- );
- }
- public static void PropertyChangingEvent(INotifyPropertyChanging inpc, Action action, Action eventAction, int fireCount = 1) {
- EventCore(
- inpc,
- action,
- eventAction,
- (o, handler) => {
- PropertyChangingEventHandler x = (sender, args) => handler(sender, args);
- inpc.PropertyChanging += x;
- return x;
- },
- (o, handler) => inpc.PropertyChanging -= handler,
- fireCount
- );
- }
- }
-}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/InterfacesTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/InterfacesTests.cs
index bfcf8cb..4f83cf3 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/InterfacesTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/InterfacesTests.cs
@@ -18,7 +18,7 @@ partial class NotImplementICU { }
[GenerateViewModel(ImplementICleanup = true)]
partial class ImplementICUParent { }
[GenerateViewModel(ImplementICleanup = true)]
- partial class ImplementICUChild { }
+ partial class ImplementICUChild : ImplementICUParent { }
[GenerateViewModel(ImplementINotifyPropertyChanging = true,
ImplementICleanup = true)]
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/NullableAnnotationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/NullableAnnotationTests.cs
index 30bebc4..e49910b 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/NullableAnnotationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/NullableAnnotationTests.cs
@@ -34,6 +34,7 @@ void NonNullableParameter1(string str) { }
int? nullableInt2;
[GenerateProperty]
string string2;
+#pragma warning disable 8632
[GenerateProperty]
string? nullableString2;
@@ -47,5 +48,6 @@ void NonNullableParameter2(string str) { }
Task NonNullableParameterAsync2(string str) => Task.CompletedTask;
void OnString1Changed(string str) { }
+#pragma warning restore 8632
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/PropertyGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/PropertyGenerationTests.cs
index 174cf37..fca85df 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/PropertyGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/PropertyGenerationTests.cs
@@ -13,7 +13,7 @@ partial class WithTwoMvvmAttribute {
[DevExpress.Mvvm.CodeGenerators.GenerateProperty]
int dxProperty;
[DevExpress.Mvvm.CodeGenerators.GenerateCommand]
- void DxMethod() { }
+ void DxMethod() { dxProperty++; }
}
[TestFixture]
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/UsingRaiseMethodTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/UsingRaiseMethodTests.cs
index 8a1ed2f..f17821b 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/UsingRaiseMethodTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/UsingRaiseMethodTests.cs
@@ -3,6 +3,7 @@
using System.ComponentModel;
using DevExpress.Mvvm.CodeGenerators.MvvmLight;
using GalaSoft.MvvmLight;
+using DevExpress.Mvvm.CodeGenerators.Tests;
namespace MvvmLight.Mvvm.Tests {
[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
@@ -22,6 +23,11 @@ partial class ChildWithParentsGeneratedRaiseMethod : ParentWithGeneraetedRaiseMe
class ParentWithoutRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
+ public ParentWithoutRaiseMethod() {
+ //avoid warnings
+ PropertyChanged?.Invoke(null, null);
+ PropertyChanging?.Invoke(null, null);
+ }
}
[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
partial class ChildWithoutRaiseMethod : ParentWithoutRaiseMethod {
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AsyncCommandGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AsyncCommandGenerationTests.cs
new file mode 100644
index 0000000..d160198
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AsyncCommandGenerationTests.cs
@@ -0,0 +1,82 @@
+using NUnit.Framework;
+using System;
+using System.Reflection;
+using System.Threading.Tasks;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm.Input;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ [GenerateViewModel]
+ partial class GenerateAsyncCommands {
+ readonly Task task = new(() => 1);
+ [GenerateCommand]
+ public Task WithNoArg() => Task.CompletedTask;
+ [GenerateCommand]
+ public Task WithArg(int arg) => Task.CompletedTask;
+ [GenerateCommand]
+ public Task WithNullableArg(int? arg) => Task.CompletedTask;
+ public Task SomeMethod() => Task.CompletedTask;
+
+ [GenerateCommand(Name = "MyAsyncCommand", CanExecuteMethod = "CanDoIt")]
+ public Task Method(int arg) => Task.CompletedTask;
+ public bool CanDoIt(int arg) => arg > 0;
+
+ [GenerateCommand]
+ public Task GenericTask() => task;
+ }
+
+ [TestFixture]
+ public class AsyncCommandGenerationTests {
+ [Test]
+ public void CallRequiredMethodForAsyncCommand() {
+ var generated = new GenerateAsyncCommands();
+
+ var method = GetFieldValue, RelayCommand>(generated.MyAsyncCommand, "execute");
+ StringAssert.Contains("MyAsyncCommand", method.Method.Name);
+
+ var canMethod = GetFieldValue, RelayCommand>(generated.MyAsyncCommand, "canExecute");
+ var expectedCanMethod = generated.GetType().GetMethod("CanDoIt").Name;
+ Assert.AreEqual(expectedCanMethod, canMethod.Method.Name);
+
+ var canExecuteMethod = GetFieldValue, RelayCommand>(generated.GenericTaskCommand, "canExecute");
+ Assert.IsNull(canExecuteMethod);
+ }
+
+ static TResult GetFieldValue(T source, string fieldName) {
+ var fieldInfo = source.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
+ Assert.IsNotNull(fieldInfo);
+
+ return (TResult)fieldInfo.GetValue(source);
+ }
+ [Test]
+ public void AsyncCommandImplementation() {
+ var generated = new GenerateAsyncCommands();
+
+ Assert.IsNotNull(generated.GetType().GetProperty("WithNoArgCommand"));
+ Assert.IsNotNull(generated.GetType().GetProperty("WithArgCommand"));
+ Assert.IsNotNull(generated.GetType().GetProperty("WithNullableArgCommand"));
+
+ Assert.IsNull(generated.GetType().GetProperty("With2ArgsCommand"));
+ Assert.IsNull(generated.GetType().GetProperty("ReturnNoTaskCommand"));
+ Assert.IsNull(generated.GetType().GetProperty("SomeMethodCommand"));
+ }
+
+ [Test]
+ public void ArgumentTypeForAsyncCommand() {
+ var generated = new GenerateAsyncCommands();
+
+ var noArgumentType = generated.WithNoArgCommand.GetType();
+ Assert.IsEmpty(noArgumentType.GetGenericArguments());
+ var expectedType = typeof(RelayCommand);
+ Assert.AreEqual(expectedType, noArgumentType);
+
+ var intArgumentType = generated.WithArgCommand.GetType().GetGenericArguments()[0];
+ var intExpectedType = typeof(int);
+ Assert.AreEqual(intExpectedType, intArgumentType);
+
+ var nullableIntArgumentType = generated.WithNullableArgCommand.GetType().GetGenericArguments()[0];
+ var nullableIntExpectedType = typeof(int?);
+ Assert.AreEqual(nullableIntExpectedType, nullableIntArgumentType);
+ }
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AttributeTransferTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AttributeTransferTests.cs
new file mode 100644
index 0000000..54d86f2
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/AttributeTransferTests.cs
@@ -0,0 +1,51 @@
+using DevExpress.Mvvm.CodeGenerators.Tests.Included;
+using NUnit.Framework;
+using System;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ class MyCustomAttribute : Attribute {
+ public MyCustomAttribute(int value, string str, bool condition, TestEnum testEnum) { }
+ }
+ namespace Included {
+ enum TestEnum {
+ Num = 1,
+ String = 2
+ }
+ }
+ [GenerateViewModel]
+ partial class AttributeTransfer {
+ const int number = 1;
+
+ [GenerateProperty]
+ int noAttribute;
+
+ [GenerateProperty, System.ComponentModel.DataAnnotations.Range(0, 1)]
+ [Required, MyCustom(number,
+ "Some string",
+ true, TestEnum.Num)]
+ int withMultipleAttributes;
+ }
+
+ [TestFixture]
+ public class AttributeTransferTests {
+ [Test]
+ public void AttributeTransferTest() {
+ var noAttributeProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.NoAttribute));
+ var attributes = Attribute.GetCustomAttributes(noAttributeProperty);
+ var expectedAttributes = new Attribute[] { };
+ Assert.AreEqual(expectedAttributes, attributes);
+
+ var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.WithMultipleAttributes));
+ attributes = Attribute.GetCustomAttributes(withMultipleAttributesProperty);
+ expectedAttributes = new Attribute[] {
+ new System.ComponentModel.DataAnnotations.RangeAttribute(0, 1),
+ new RequiredAttribute(),
+ new MyCustomAttribute(1, "Some string", true, TestEnum.Num)
+ };
+ Assert.AreEqual(expectedAttributes, attributes);
+ }
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/CommandGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/CommandGenerationTests.cs
similarity index 78%
rename from DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/CommandGenerationTests.cs
rename to DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/CommandGenerationTests.cs
index 533366f..b00d415 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmLightTest/CommandGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/CommandGenerationTests.cs
@@ -1,17 +1,12 @@
using NUnit.Framework;
using System;
using System.Reflection;
-using DevExpress.Mvvm.CodeGenerators.MvvmLight;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
using GalaSoft.MvvmLight.Helpers;
+using Microsoft.Toolkit.Mvvm.Input;
using System.Linq;
-#if NETCOREAPP
-using GalaSoft.MvvmLight.Command;
-#else
-using GalaSoft.MvvmLight.CommandWpf;
-#endif
-
-namespace MvvmLight.Mvvm.Tests {
+namespace MvvmToolkit.Mvvm.Tests {
[GenerateViewModel]
partial class GenerateCommands {
[GenerateCommand]
@@ -31,7 +26,7 @@ public void Method(int arg) { }
[GenerateCommand]
void WithNullableString1(string? str) { }
[GenerateCommand]
- void WithNullableString2(string str) { }
+ void WithNullableString2(string? str) { }
[GenerateCommand]
void WithNullableString3(string? str) { }
bool CanWithNullableString3(string str) => str.Length > 0;
@@ -72,24 +67,23 @@ public void CommandImplementation() {
public void CallRequiredMethodForCommand() {
var generated = new GenerateCommands();
+ var executeMethodWithNoArg = GetFieldValue, RelayCommand>(generated.WithNullableArgCommand, "execute");
var expectedExecuteMethodWithNoArg = generated.GetType().GetMethod("WithNullableArg");
- var executeMethodWithNoArg = GetFieldValueMethod, WeakAction>(generated.WithNullableArgCommand, "_execute");
- Assert.AreEqual(expectedExecuteMethodWithNoArg, executeMethodWithNoArg);
+ Assert.AreEqual(expectedExecuteMethodWithNoArg, executeMethodWithNoArg.Method);
- var method = GetFieldValueMethod, WeakAction>(generated.Command, "_execute");
+ var method = GetFieldValue, RelayCommand>(generated.Command, "execute");
var expectedMethod = generated.GetType().GetMethod("Method");
- Assert.AreEqual(expectedMethod, method);
+ Assert.AreEqual(expectedMethod, method.Method);
- var canMethod = GetFieldValueMethod, WeakFunc>(generated.Command, "_canExecute");
+ var canMethod = GetFieldValue, RelayCommand>(generated.Command, "canExecute");
var expectedCanMethod = generated.GetType().GetMethod("CanDoIt");
- Assert.AreEqual(expectedCanMethod, canMethod);
+ Assert.AreEqual(expectedCanMethod, canMethod.Method);
}
- static TResult GetFieldValueMethod(TCommand source, string fieldName) {
+ static TResult GetFieldValue(T source, string fieldName) {
var fieldInfo = source.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
Assert.IsNotNull(fieldInfo);
- var fieldInsance = fieldInfo.GetValue(source);
- var weakMethod = typeof(T).GetProperty("Method", BindingFlags.NonPublic | BindingFlags.Instance);
- return (TResult)weakMethod.GetValue(fieldInsance);
+
+ return (TResult)fieldInfo.GetValue(source);
}
[Test]
public void ArgumentTypeForCommand() {
@@ -129,9 +123,10 @@ public void AttributeGenerationTest() {
var generated = new GenerateCommands();
var attributes = generated.GetType().GetProperty("AttributeTestCommand").GetCustomAttributes().ToList();
- Assert.AreEqual(2, attributes.Count);
- Assert.IsTrue(attributes[0] is FirstAttribute);
- Assert.IsTrue(attributes[1] is ThirdAttribute);
+ Assert.AreEqual(3, attributes.Count);
+ Assert.IsTrue(attributes[0].GetType().Name == "NullableAttribute");
+ Assert.IsTrue(attributes[1] is FirstAttribute);
+ Assert.IsTrue(attributes[2] is ThirdAttribute);
}
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/InterfacesTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/InterfacesTests.cs
new file mode 100644
index 0000000..6b01fdc
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/InterfacesTests.cs
@@ -0,0 +1,69 @@
+using NUnit.Framework;
+using System.ComponentModel;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using GalaSoft.MvvmLight;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ partial class SimpleClass { }
+ [GenerateViewModel]
+ partial class ClassWithGenerator { }
+
+ [GenerateViewModel(ImplementINotifyPropertyChanging = false)]
+ partial class NotImplementINPCing { }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ImplementINPCing { }
+
+ [GenerateViewModel]
+ partial class ChildWithInheritedUserINPC : ViewModelBase { }
+
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class GeneratedParent { }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class GeneratedChild : GeneratedParent {
+ [GenerateProperty]
+ int value;
+ }
+
+ [TestFixture]
+ public class IntefacesTests {
+ [Test]
+ public void INPCedImplimentation() {
+ var withGenerator = new ClassWithGenerator();
+ Assert.IsTrue(withGenerator is INotifyPropertyChanged);
+
+ var withoutGenerator = new SimpleClass();
+ Assert.IsTrue(withoutGenerator is not INotifyPropertyChanged);
+ }
+
+ [Test]
+ public void INPCingImplementation() {
+ var inpcingDefault = new ClassWithGenerator();
+ Assert.IsTrue(inpcingDefault is not INotifyPropertyChanging);
+
+ var inpcingImpl = new ImplementINPCing();
+ Assert.IsTrue(inpcingImpl is INotifyPropertyChanging);
+
+ var inpcingNotImpl = new NotImplementINPCing();
+ Assert.IsTrue(inpcingNotImpl is not INotifyPropertyChanging);
+ }
+
+ [Test]
+ public void InheritanceUserINPC() {
+ var child = new ChildWithInheritedUserINPC();
+
+ Assert.IsTrue(child is INotifyPropertyChanged);
+ Assert.IsTrue(child is not INotifyPropertyChanging);
+ }
+
+ [Test]
+ public void InheritanceGeneratedINPC() {
+ var parent = new GeneratedParent();
+ var child = new GeneratedChild();
+
+ Assert.IsTrue(parent is INotifyPropertyChanged);
+ Assert.IsTrue(parent is INotifyPropertyChanging);
+ Assert.IsTrue(child is INotifyPropertyChanged);
+ Assert.IsTrue(child is INotifyPropertyChanging);
+ }
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/NullableAnnotationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/NullableAnnotationTests.cs
new file mode 100644
index 0000000..dcc87ed
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/NullableAnnotationTests.cs
@@ -0,0 +1,48 @@
+using System.Threading.Tasks;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ public partial class NullableAnnotation {
+#nullable enable
+ public NullableAnnotation() {
+ string1 = "123";
+ }
+ [GenerateProperty]
+ int int1;
+ [GenerateProperty]
+ int? nullableInt1;
+ [GenerateProperty]
+ string string1;
+ [GenerateProperty]
+ string? nullableString1;
+
+ [GenerateCommand]
+ void NullableParameter1(string? str) { }
+ [GenerateCommand]
+ Task NullableParameterAsync1(string? str) => Task.CompletedTask;
+
+#nullable disable
+ [GenerateProperty]
+ int int2;
+ [GenerateProperty]
+ int? nullableInt2;
+ [GenerateProperty]
+ string string2;
+#pragma warning disable 8632
+ [GenerateProperty]
+ string? nullableString2;
+
+ [GenerateCommand]
+ void NullableParameter2(string? str) { }
+ [GenerateCommand]
+ void NonNullableParameter2(string str) { }
+ [GenerateCommand]
+ Task NullableParameterAsync2(string? str) => Task.CompletedTask;
+ [GenerateCommand]
+ Task NonNullableParameterAsync2(string str) => Task.CompletedTask;
+
+ void OnString1Changed(string str) { }
+#pragma warning restore 8632
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/PropertyGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/PropertyGenerationTests.cs
new file mode 100644
index 0000000..7b6b8c1
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/PropertyGenerationTests.cs
@@ -0,0 +1,90 @@
+using NUnit.Framework;
+using System.ComponentModel;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+using Microsoft.Toolkit.Mvvm.Messaging;
+using Microsoft.Toolkit.Mvvm.Messaging.Messages;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class GenerateProperties {
+ [GenerateProperty(IsVirtual = true)]
+ int property;
+ }
+ [GenerateViewModel]
+ partial class WithTwoMvvmAttribute {
+ [DevExpress.Mvvm.CodeGenerators.GenerateProperty]
+ int dxProperty;
+ [DevExpress.Mvvm.CodeGenerators.GenerateCommand]
+ void DxMethod() { dxProperty++; }
+ }
+
+ [GenerateViewModel]
+ partial class Broadcast : ObservableRecipient {
+ public Broadcast(IMessenger messenger) : base(messenger) {
+ }
+ [GenerateProperty(Broadcast = true)]
+ int value;
+ }
+
+ [GenerateViewModel]
+ partial class Validator : ObservableValidator {
+ [System.ComponentModel.DataAnnotations.Range(0, 9)]
+ [GenerateProperty(Validate = true)]
+ int value;
+ }
+
+
+ [TestFixture]
+ public class PropertyGenerationTests {
+ [Test]
+ public void PropertyImplementation() {
+ var generated = new GenerateProperties();
+
+ Assert.IsNotNull(generated.GetType().GetProperty("Property"));
+ Assert.IsNull(generated.GetType().GetProperty("NotProperty"));
+ }
+ [Test]
+ public void DoNotGenerateDxMembers() {
+ var generated = new WithTwoMvvmAttribute();
+
+ Assert.IsNull(generated.GetType().GetProperty("DxProperty"));
+ Assert.IsNull(generated.GetType().GetProperty("DxMethodCommand"));
+ }
+#if !FRAMEWORK
+ [Test]
+ public void BroadcastProperty() {
+ var messenger = new StrongReferenceMessenger();
+ var broadcast = new Broadcast(messenger) { IsActive = true };
+
+ int messageCount = 0;
+ messenger.Register>(this, (r, m) => {
+ Assert.AreEqual(r, this);
+ Assert.AreEqual(0, m.OldValue);
+ Assert.AreEqual(1, m.NewValue);
+ Assert.AreEqual("Value", m.PropertyName);
+ Assert.AreEqual(broadcast, m.Sender);
+ Assert.AreEqual(1, broadcast.Value);
+ messageCount++;
+ });
+ broadcast.Value = 1;
+ Assert.AreEqual(1, messageCount);
+ broadcast.Value = 1;
+ Assert.AreEqual(1, messageCount);
+ }
+ [Test]
+ public void ValidateProperty() {
+ var validator = new Validator();
+ int messageCount = 0;
+
+ validator.ErrorsChanged += (o, e) => {
+ Assert.AreEqual("Value", e.PropertyName);
+ Assert.AreEqual(validator, o);
+ messageCount++;
+ };
+ validator.Value = 13;
+ Assert.AreEqual(1, messageCount);
+ }
+#endif
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/UsingRaiseMethodTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/UsingRaiseMethodTests.cs
new file mode 100644
index 0000000..64fa000
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/MvvmToolkit/UsingRaiseMethodTests.cs
@@ -0,0 +1,140 @@
+using NUnit.Framework;
+using System;
+using System.ComponentModel;
+using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm;
+using DevExpress.Mvvm.CodeGenerators.Tests;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class DefaultRaiseMethod {
+ [GenerateProperty]
+ int value;
+ }
+
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ParentWithGeneraetedRaiseMethod { }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithParentsGeneratedRaiseMethod : ParentWithGeneraetedRaiseMethod {
+ [GenerateProperty]
+ int value;
+ }
+
+ class ParentWithoutRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public event PropertyChangingEventHandler PropertyChanging;
+ public ParentWithoutRaiseMethod() {
+ //avoid warnings
+ PropertyChanged?.Invoke(null, null);
+ PropertyChanging?.Invoke(null, null);
+ }
+ }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithoutRaiseMethod : ParentWithoutRaiseMethod {
+ // Has error DXCG0008! Look at DiagnosticTest.cs/RaiseMethodNotFoundDiagnostic()
+ }
+
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ParentWithImplementationAndGeneratedRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public event PropertyChangingEventHandler PropertyChanging;
+ }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithParentsGeneratedRaiseMethod2 : ParentWithImplementationAndGeneratedRaiseMethod {
+ [GenerateProperty]
+ int value;
+ }
+
+ class ParentWithEventArgsParameterRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public event PropertyChangingEventHandler PropertyChanging;
+
+ protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs) => PropertyChanged?.Invoke(this, eventArgs);
+ protected void OnPropertyChanging(PropertyChangingEventArgs eventArgs) => PropertyChanging?.Invoke(this, eventArgs);
+ }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithParentsImplementedRaiseMethod : ParentWithEventArgsParameterRaiseMethod {
+ [GenerateProperty]
+ int value;
+ }
+
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithParentsStringParameterRaiseMethod4 : ObservableObject {
+ [GenerateProperty]
+ int value;
+ }
+
+ [TestFixture]
+ class UsingRaiseMethodTests {
+ [Test]
+ public void DefaultRaiseMethod() {
+ var generated = new DefaultRaiseMethod();
+ Assert.Throws(() =>
+ DoWith.PropertyChangedEvent(
+ generated,
+ () => DoWith.PropertyChangingEvent(
+ generated,
+ () => generated.Value = 1,
+ e => throw new Exception()),
+ e => throw new Exception())
+ );
+ }
+
+ [Test]
+ public void ParentsGeneratedRaiseMethod() {
+ var generated = new ChildWithParentsGeneratedRaiseMethod();
+ Assert.Throws(() =>
+ DoWith.PropertyChangedEvent(
+ generated,
+ () => DoWith.PropertyChangingEvent(
+ generated,
+ () => generated.Value = 1,
+ e => throw new Exception()),
+ e => throw new Exception())
+ );
+ }
+
+ [Test]
+ public void ParentWithImplementationAndGeneratedRaiseMethod() {
+ var generated = new ChildWithParentsGeneratedRaiseMethod2();
+ Assert.Throws(() =>
+ DoWith.PropertyChangedEvent(
+ generated,
+ () => DoWith.PropertyChangingEvent(
+ generated,
+ () => generated.Value = 1,
+ e => throw new Exception()),
+ e => throw new Exception())
+ );
+ }
+
+ [Test]
+ public void ParentWithEventArgsParameterRaiseMethod() {
+ var generated = new ChildWithParentsImplementedRaiseMethod();
+ Assert.Throws(() =>
+ DoWith.PropertyChangedEvent(
+ generated,
+ () => DoWith.PropertyChangingEvent(
+ generated,
+ () => generated.Value = 1,
+ e => throw new Exception()),
+ e => throw new Exception())
+ );
+ }
+
+ [Test]
+ public void ParentWithStringParameterRaiseMethod() {
+ var generated = new ChildWithParentsStringParameterRaiseMethod4();
+ Assert.Throws(() =>
+ DoWith.PropertyChangedEvent(
+ generated,
+ () => DoWith.PropertyChangingEvent(
+ generated,
+ () => generated.Value = 1,
+ e => throw new Exception()),
+ e => throw new Exception())
+ );
+ }
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/AttributeTransferTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/AttributeTransferTests.cs
index 5d14a1b..263ee6a 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/AttributeTransferTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/AttributeTransferTests.cs
@@ -31,13 +31,13 @@ partial class AttributeTransfer {
[TestFixture]
public class AttributeTransferTests {
[Test]
- public void AttributeTransfer() {
- var noAttributeProperty = typeof(AttributeTransfer).GetProperty("NoAttribute");
+ public void AttributeTransferTest() {
+ var noAttributeProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.NoAttribute));
var attributes = Attribute.GetCustomAttributes(noAttributeProperty);
var expectedAttributes = new Attribute[] { };
Assert.AreEqual(expectedAttributes, attributes);
- var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty("WithMultipleAttributes");
+ var withMultipleAttributesProperty = typeof(AttributeTransfer).GetProperty(nameof(AttributeTransfer.WithMultipleAttributes));
attributes = Attribute.GetCustomAttributes(withMultipleAttributesProperty);
expectedAttributes = new Attribute[] {
new System.ComponentModel.DataAnnotations.RangeAttribute(0, 1),
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/Helper.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/Helper.cs
deleted file mode 100644
index 7e271ec..0000000
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/Helper.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using NUnit.Framework;
-using System;
-using System.ComponentModel;
-
-namespace Prism.Mvvm.Tests {
- static class DoWith {
- static void EventCore(
- TSender sender,
- Action action,
- Action eventAction,
- Func, THandler> subscribe,
- Action unsubscribe,
- int expectedFireCount = 1)
- where TArgs : EventArgs {
-
- var fireCount = 0;
- EventHandler handler = (o, e) => {
- Assert.AreSame(o, sender);
- eventAction(e);
- fireCount++;
- };
-
- var h = subscribe(sender, handler);
- try {
- action();
- } finally {
- unsubscribe(sender, h);
- }
- Assert.AreEqual(expectedFireCount, fireCount);
- }
-
- public static void PropertyChangedEvent(INotifyPropertyChanged inpc, Action action, Action eventAction, int fireCount = 1) {
- EventCore(
- inpc,
- action,
- eventAction,
- (o, handler) => {
- PropertyChangedEventHandler x = (sender, args) => handler(sender, args);
- inpc.PropertyChanged += x;
- return x;
- },
- (o, handler) => inpc.PropertyChanged -= handler,
- fireCount
- );
- }
- public static void PropertyChangingEvent(INotifyPropertyChanging inpc, Action action, Action eventAction, int fireCount = 1) {
- EventCore(
- inpc,
- action,
- eventAction,
- (o, handler) => {
- PropertyChangingEventHandler x = (sender, args) => handler(sender, args);
- inpc.PropertyChanging += x;
- return x;
- },
- (o, handler) => inpc.PropertyChanging -= handler,
- fireCount
- );
- }
- }
-}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/InterfacesTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/InterfacesTests.cs
index 43aefb9..15cf680 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/InterfacesTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/InterfacesTests.cs
@@ -36,6 +36,10 @@ partial class FullImplemented : INotifyPropertyChanged, INotifyPropertyChanging,
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
public event EventHandler IsActiveChanged;
+ public FullImplemented() {
+ //avoid warninngs
+ IsActiveChanged?.Invoke(null, null);
+ }
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/NullableAnnotationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/NullableAnnotationTests.cs
index 9e7d7c4..2666a0a 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/NullableAnnotationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/NullableAnnotationTests.cs
@@ -33,6 +33,7 @@ void NonNullableParameter1(string str) { }
int? nullableInt2;
[GenerateProperty]
string string2;
+#pragma warning disable 8632
[GenerateProperty]
string? nullableString2;
@@ -46,5 +47,6 @@ void NonNullableParameter2(string str) { }
Task NonNullableParameterAsync2(string str) => Task.CompletedTask;
void OnString1Changed(string str) { }
+#pragma warning restore 8632
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/PropertyGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/PropertyGenerationTests.cs
index 1a954fa..d62ba61 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/PropertyGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/PropertyGenerationTests.cs
@@ -13,7 +13,7 @@ partial class WithTwoMvvmAttribute {
[DevExpress.Mvvm.CodeGenerators.GenerateProperty]
int dxProperty;
[DevExpress.Mvvm.CodeGenerators.GenerateCommand]
- void DxMethod() { }
+ void DxMethod() { dxProperty++; }
}
[TestFixture]
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/UsingRaiseMethodTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/UsingRaiseMethodTests.cs
index 043a5d8..4813e32 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/UsingRaiseMethodTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/PrismTest/UsingRaiseMethodTests.cs
@@ -2,6 +2,7 @@
using System;
using System.ComponentModel;
using DevExpress.Mvvm.CodeGenerators.Prism;
+using DevExpress.Mvvm.CodeGenerators.Tests;
namespace Prism.Mvvm.Tests {
[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
@@ -21,6 +22,11 @@ partial class ChildWithParentsGeneratedRaiseMethod : ParentWithGeneraetedRaiseMe
class ParentWithoutRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
+ public ParentWithoutRaiseMethod() {
+ //avoid warnings
+ PropertyChanged?.Invoke(null, null);
+ PropertyChanging?.Invoke(null, null);
+ }
}
[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
partial class ChildWithoutRaiseMethod : ParentWithoutRaiseMethod {
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/SharedTests.projitems b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/SharedTests.projitems
index 94128da..325a032 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/SharedTests.projitems
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/SharedTests/SharedTests.projitems
@@ -12,7 +12,7 @@
-
+
@@ -20,16 +20,20 @@
-
-
+
+
+
+
+
+
+
-
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests.WinUI/UnitTests.WinUI.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests.WinUI/UnitTests.WinUI.csproj
index b46a2ea..4160d8c 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests.WinUI/UnitTests.WinUI.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests.WinUI/UnitTests.WinUI.csproj
@@ -6,7 +6,7 @@
9
true
- 8618,8604
+ true
@@ -23,7 +23,7 @@
- ..\..\..\2022.1\Bin\WinUI\Sdk\Mvvm\DevExpress.WinUI.Mvvm.v22.1.dll
+ ..\..\..\..\2022.1\Bin\WinUI\Sdk\Mvvm\DevExpress.WinUI.Mvvm.v22.1.dll
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmLight.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmLight.cs
index 0e9237a..8184d65 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmLight.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmLight.cs
@@ -21,12 +21,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(2, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(2, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.NoPartialModifier.Id, diagnostics[0].Id);
}
@@ -46,13 +43,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.InvalidPropertyName.Id, diagnostics[0].Id);
}
@@ -77,13 +70,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(4, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.OnChangedMethodNotFound.Id, diagnostic.Id);
@@ -108,14 +97,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[0].Id);
Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[1].Id);
@@ -155,13 +139,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(6, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.CanExecuteMethodNotFound.Id, diagnostic.Id);
@@ -188,13 +168,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.RaiseMethodNotFound.Id, diagnostic.Id);
@@ -223,13 +199,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.TwoSuitableMethods.Id, diagnostic.Id);
@@ -243,33 +215,17 @@ public void TwoGenerateViewModelAttributeDiagnostic(string generateViewModel) {
partial class TwoGenerateViewModelAttributeClass { }
}
";
- Compilation inputCompilation = CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(sourceCode) },
- new[] {
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(RelayCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(Prism.Commands.DelegateCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(DevExpress.Mvvm.DelegateCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(INotifyPropertyChanged).Assembly.Location),
- },
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- ViewModelGenerator generator = new ViewModelGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- var asdf = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(GeneratorHelper.CreateCompilation(sourceCode, new[] {
+ typeof(INotifyPropertyChanged),
+ typeof(RelayCommand),
+ typeof(Prism.Commands.DelegateCommand),
+ typeof(DevExpress.Mvvm.DelegateCommand),
+ }));
Assert.AreEqual(GeneratorDiagnostics.MoreThanOneGenerateViewModelAttributes.Id, diagnostics[0].Id);
- Assert.AreEqual(4, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(4, trees.Count());
}
public static Compilation CreateCompilation(string source) =>
- CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- new[] {
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(RelayCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(INotifyPropertyChanged).Assembly.Location),
- },
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+ GeneratorHelper.CreateCompilation(source, new[] { typeof(INotifyPropertyChanged), typeof(RelayCommand) });
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmToolkit.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmToolkit.cs
new file mode 100644
index 0000000..f74047c
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestMvvmToolkit.cs
@@ -0,0 +1,272 @@
+using Microsoft.Toolkit.Mvvm.Input;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using NUnit.Framework;
+using System.ComponentModel;
+using System.Linq;
+using System.Collections.Immutable;
+using System.Collections.Generic;
+
+namespace DevExpress.Mvvm.CodeGenerators.Tests {
+ [TestFixture]
+ public class DiagnosticTestsMvvmToolkit {
+ [Test]
+ public void NoPartialDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace Test {
+ [GenerateViewModel]
+ class NoPartialClass { }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(2, trees.Count());
+ Assert.AreEqual(GeneratorDiagnostics.NoPartialModifier.Id, diagnostics[0].Id);
+ }
+
+ [Test]
+ public void InvalidPropertyNameDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class WithProperty {
+ [GenerateProperty]
+ int Property;
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(GeneratorDiagnostics.InvalidPropertyName.Id, diagnostics[0].Id);
+ }
+
+ [Test]
+ public void OnChangedMethodNotFoundDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class OnChangedMethodNotFound {
+ [GenerateProperty(OnChangedMethod = ""NotCreatedChangedMethod"", OnChangingMethod = ""NotCreatedChangingMethod"")]
+ int value1;
+ [GenerateProperty(OnChangedMethod = ""IncorrectSignatureChangedMethod"", OnChangingMethod = ""IncorrectSignatureChangingMethod"")]
+ int value2;
+
+ public int IncorrectSignatureChangedMethod() { return 1; }
+ public void IncorrectSignatureChangingMethod(int arg1, int arg2) { }
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(4, diagnostics.Count());
+ foreach(var diagnostic in diagnostics)
+ Assert.AreEqual(GeneratorDiagnostics.OnChangedMethodNotFound.Id, diagnostic.Id);
+ }
+
+ [Test]
+ public void IncorrectCommandSignatureDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class WithCommand {
+ [GenerateCommand]
+ public int Command1() {}
+
+ [GenerateCommand]
+ public void Command2(int a, int b) {}
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+
+ Assert.AreEqual(2, diagnostics.Count());
+ Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[0].Id);
+ Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[1].Id);
+ }
+
+ [Test]
+ public void CanExecuteMethodNotFoundDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using System.Threading.Tasks;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class CanExecuteMethodNotFound {
+ [GenerateCommand(CanExecuteMethod = ""WrongParameter"")]
+ public void Command1(int arg) { }
+ [GenerateCommand(CanExecuteMethod = ""NoCreated"")]
+ public void Command2(int arg) { }
+ [GenerateCommand(CanExecuteMethod = ""ReturnNoBool"")]
+ public void Command3(int arg) { }
+
+ [GenerateCommand(CanExecuteMethod = ""WrongParameter"")]
+ public Task AsyncCommand1(int arg) => Task.CompletedTask;
+ [GenerateCommand(CanExecuteMethod = ""NoCreated"")]
+ public Task AsyncCommand2(int arg) => Task.CompletedTask;
+ [GenerateCommand(CanExecuteMethod = ""ReturnNoBool"")]
+ public Task AsyncCommand3(int arg) => Task.CompletedTask;
+
+ public bool WrongParameter() => true;
+ public bool WrongParameter(string arg) => arg.Length > 0;
+ public bool WrongParameter(int arg1, int arg2) => arg1 > arg2;
+
+ public int ReturnNoBool(int arg) => arg;
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(6, diagnostics.Count());
+ foreach(var diagnostic in diagnostics)
+ Assert.AreEqual(GeneratorDiagnostics.CanExecuteMethodNotFound.Id, diagnostic.Id);
+ }
+
+ [Test]
+ public void RaiseMethodNotFoundDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using System.ComponentModel;
+
+namespace Test {
+ class ParentWithoutRaiseMethod : INotifyPropertyChanged, INotifyPropertyChanging {
+ public event PropertyChangedEventHandler PropertyChanged;
+ public event PropertyChangingEventHandler PropertyChanging;
+ }
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ChildWithoutRaiseMethod : ParentWithoutRaiseMethod {
+ [GenerateProperty]
+ int value;
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(2, diagnostics.Count());
+ foreach(var diagnostic in diagnostics)
+ Assert.AreEqual(GeneratorDiagnostics.OnMethodNotFound.Id, diagnostic.Id);
+ }
+
+ [Test]
+ public void TwoSuitableMethodsDiagnostic() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using System.Threading.Tasks;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class TwoSuitableMethods {
+ [GenerateProperty(OnChangedMethod = ""TwoChangedMethods"", OnChangingMethod = ""TwoChangingMethods"")]
+ int value;
+
+ public void TwoChangedMethods() { }
+ public void TwoChangedMethods(int arg) { }
+
+ public void TwoChangingMethods() { }
+ public void TwoChangingMethods(int arg) { }
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(2, diagnostics.Count());
+ foreach(var diagnostic in diagnostics)
+ Assert.AreEqual(GeneratorDiagnostics.TwoSuitableMethods.Id, diagnostic.Id);
+ }
+ [Test]
+ public void NoBaseObservableRecipientClass() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class Broadcast {
+ [GenerateProperty(Broadcast = true)]
+ int value;
+ public Broadcast() => value.ToString(); //avoid not used warning
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(GeneratorDiagnostics.NoBaseObservableRecipientClass.Id, diagnostics.Single().Id);
+ }
+ [Test]
+ public void NoBaseObservableValidatorClass() {
+ var sourceCode = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm.ComponentModel;
+
+namespace Test {
+ [GenerateViewModel]
+ partial class Validator {
+ [GenerateProperty(Validate = true)]
+ int value;
+ public Validator() => value.ToString(); //avoid not used warning
+ }
+}
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
+ Assert.AreEqual(3, trees.Count());
+ Assert.AreEqual(GeneratorDiagnostics.NoBaseObservableValidatorClass.Id, diagnostics.Single().Id);
+ }
+ [TestCase("[DevExpress.Mvvm.CodeGenerators.Prism.GenerateViewModel]\r\n")]
+ [TestCase("[DevExpress.Mvvm.CodeGenerators.GenerateViewModel]\r\n")]
+ public void TwoGenerateViewModelAttributeDiagnostic(string generateViewModel) {
+ var sourceCode = "namespace Test {\r\n"
+ + generateViewModel +
+ @"[DevExpress.Mvvm.CodeGenerators.MvvmToolkit.GenerateViewModel]
+ partial class TwoGenerateViewModelAttributeClass { }
+ }
+";
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(GeneratorHelper.CreateCompilation(sourceCode, new[] {
+ typeof(INotifyPropertyChanged),
+ typeof(RelayCommand),
+ typeof(Prism.Commands.DelegateCommand),
+ typeof(DevExpress.Mvvm.DelegateCommand),
+ }));
+
+ Assert.AreEqual(GeneratorDiagnostics.MoreThanOneGenerateViewModelAttributes.Id, diagnostics[0].Id);
+ Assert.AreEqual(4, trees.Count());
+ }
+ public static Compilation CreateCompilation(string source) =>
+ GeneratorHelper.CreateCompilation(source, new[] { typeof(INotifyPropertyChanged), typeof(RelayCommand) });
+ }
+}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsDx.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsDx.cs
index f75fa25..956c273 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsDx.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsDx.cs
@@ -20,12 +20,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(2, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(2, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.NoPartialModifier.Id, diagnostics[0].Id);
}
@@ -45,13 +42,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.InvalidPropertyName.Id, diagnostics[0].Id);
}
@@ -76,13 +69,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(4, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.OnChangedMethodNotFound.Id, diagnostic.Id);
@@ -107,13 +96,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[0].Id);
@@ -154,13 +139,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(6, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.CanExecuteMethodNotFound.Id, diagnostic.Id);
@@ -187,13 +168,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.RaiseMethodNotFound.Id, diagnostic.Id);
@@ -222,26 +199,17 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.TwoSuitableMethods.Id, diagnostic.Id);
}
public static Compilation CreateCompilation(string source) =>
- CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- new[] {
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(DelegateCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(INotifyPropertyChanged).Assembly.Location),
- },
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+ GeneratorHelper.CreateCompilation(source, new[] {
+ typeof(INotifyPropertyChanged),
+ typeof(DelegateCommand),
+ });
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsPrism.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsPrism.cs
index 1b7bb37..ba8c0df 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsPrism.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/DiagnosticTests/DiagnosticTestsPrism.cs
@@ -20,12 +20,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(2, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(2, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.NoPartialModifier.Id, diagnostics[0].Id);
}
@@ -45,13 +42,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(GeneratorDiagnostics.InvalidPropertyName.Id, diagnostics[0].Id);
}
@@ -76,13 +69,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(4, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.OnChangedMethodNotFound.Id, diagnostic.Id);
@@ -107,13 +96,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
Assert.AreEqual(GeneratorDiagnostics.IncorrectCommandSignature.Id, diagnostics[0].Id);
@@ -154,13 +139,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(6, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.CanExecuteMethodNotFound.Id, diagnostic.Id);
@@ -187,13 +168,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.RaiseMethodNotFound.Id, diagnostic.Id);
@@ -219,13 +196,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.NonNullableDelegateCommandArgument.Id, diagnostic.Id);
@@ -254,13 +227,9 @@ public static void Main(string[] args) { }
}
}
";
- Compilation inputCompilation = CreateCompilation(sourceCode);
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(CreateCompilation(sourceCode));
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
Assert.AreEqual(2, diagnostics.Count());
foreach(var diagnostic in diagnostics)
Assert.AreEqual(GeneratorDiagnostics.TwoSuitableMethods.Id, diagnostic.Id);
@@ -284,22 +253,12 @@ partial class TwoGenerateViewModelAttributeClass { }
MetadataReference.CreateFromFile(typeof(INotifyPropertyChanged).Assembly.Location),
},
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- ViewModelGenerator generator = new ViewModelGenerator();
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ var (trees, diagnostics) = GeneratorHelper.GetDiagnostics(inputCompilation);
Assert.AreEqual(GeneratorDiagnostics.MoreThanOneGenerateViewModelAttributes.Id, diagnostics[0].Id);
- Assert.AreEqual(3, outputCompilation.SyntaxTrees.Count());
+ Assert.AreEqual(3, trees.Count());
}
public static Compilation CreateCompilation(string source) =>
- CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- new[] {
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(Prism.Commands.DelegateCommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(INotifyPropertyChanged).Assembly.Location),
- },
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+ GeneratorHelper.CreateCompilation(source, new[] { typeof(INotifyPropertyChanged), typeof(Prism.Commands.DelegateCommand) });
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/CommonGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/CommonGenerationTests.cs
index a9e2b4b..4526f8d 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/CommonGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/CommonGenerationTests.cs
@@ -2,6 +2,8 @@
using Microsoft.CodeAnalysis.CSharp;
using NUnit.Framework;
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Text.RegularExpressions;
namespace DevExpress.Mvvm.CodeGenerators.Tests {
@@ -163,25 +165,7 @@ public void Command1(int arg) { }
}
static string GenerateCode(string source) {
- var references = new[] {
- MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- };
- Compilation inputCompilation = CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- references,
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- GeneratorDriverRunResult runResult = driver.GetRunResult();
- GeneratorRunResult generatorResult = runResult.Results[0];
-
- var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString();
- return generatedCode;
+ return GeneratorHelper.GenerateCode(source, null);
}
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmLight.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmLight.cs
index e0d482a..ae70038 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmLight.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmLight.cs
@@ -5,6 +5,7 @@
using Prism.Commands;
using DevExpress.Mvvm.CodeGenerators;
using GalaSoft.MvvmLight.Command;
+using DevExpress.Mvvm.CodeGenerators.Tests;
namespace MvvmLight.Mvvm.Tests {
[TestFixture]
@@ -52,7 +53,7 @@ public static void Main(string[] args) { }
}
[Test]
- public void PrismUsing_Command() {
+ public void Using_Command() {
var source = @"
using DevExpress.Mvvm.CodeGenerators.MvvmLight;
namespace Test {
@@ -139,26 +140,7 @@ partial class Example {
}
static string GenerateCode(string source) {
- var references = new[] {
- MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(RelayCommand).Assembly.Location),
- };
- Compilation inputCompilation = CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- references,
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- GeneratorDriverRunResult runResult = driver.GetRunResult();
- GeneratorRunResult generatorResult = runResult.Results[0];
-
- var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString();
- return generatedCode;
+ return GeneratorHelper.GenerateCode(source, typeof(RelayCommand));
}
[Test]
public void FormattingTest() {
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmToolkit.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmToolkit.cs
new file mode 100644
index 0000000..53b5030
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsMvvmToolkit.cs
@@ -0,0 +1,343 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using NUnit.Framework;
+using System;
+using DevExpress.Mvvm.CodeGenerators;
+using Microsoft.Toolkit.Mvvm;
+using Microsoft.Toolkit.Mvvm.Input;
+using Microsoft.Toolkit.Mvvm.Messaging;
+using DevExpress.Mvvm.CodeGenerators.Tests;
+
+namespace MvvmToolkit.Mvvm.Tests {
+ [TestFixture]
+ public class GenerationTestsMvvmToolkit {
+ [Test]
+ public void GenerationFormat() {
+ var source = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+ namespace Test {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class ExamplePrism {
+ [GenerateProperty]
+ [System.ComponentModel.DataAnnotations.Range(0,
+ 1)]
+ int property;
+
+ [GenerateCommand]
+ public void Method(int? arg) { }
+ }
+
+ public class Program {
+ public static void Main(string[] args) { }
+ }
+ }
+ ";
+ string generatedCode = GenerateCode(source);
+ var tabs = 0;
+ foreach(var str in generatedCode.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) {
+ if(string.IsNullOrEmpty(str))
+ continue;
+
+ if(str.Contains("}") && !str.Contains("{"))
+ if(str.EndsWith("}"))
+ tabs--;
+ else
+ Assert.Fail();
+
+ var expectedLeadingWhitespaceCount = tabs * 4;
+ var leadingWhitespaceCount = str.Length - str.TrimStart().Length;
+ Assert.AreEqual(expectedLeadingWhitespaceCount, leadingWhitespaceCount);
+
+ if(str.EndsWith("{"))
+ tabs++;
+ }
+ }
+
+ [Test]
+ public void Using_Command() {
+ var source = @"
+ using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+ namespace Test {
+ [GenerateViewModel]
+ partial class Example {
+ [GenerateCommand]
+ public void Method(int arg) { }
+ }
+ }";
+ string generatedCode = GenerateCode(source);
+ StringAssert.Contains("using Microsoft.Toolkit.Mvvm.Input;", generatedCode);
+ StringAssert.Contains("MethodCommand", generatedCode);
+ }
+ [Test]
+ public void GenerateComments() {
+ var source = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+ namespace Test {
+ [GenerateViewModel]
+ partial class Example {
+
+ // Ordinary comment
+ ///
+ /// Ignorable comment
+ ///
+
+ ///
+ /// Test property comment
+ ///
+ // Ordinary comment
+ [GenerateProperty]
+ int property;
+
+ /**
+
+ MultiLine Comment
+
+ */
+ [GenerateProperty]
+ int property2;
+
+ ///
+ /// Test command comment
+ ///
+ [GenerateCommand]
+ public void Method(int? arg) { }
+ }
+ }
+ ";
+ var propertyComment =
+@" ///
+ /// Test command comment
+ /// ";
+ var property2Comment =
+@" /**
+
+ MultiLine Comment
+
+ */";
+ var commandComment =
+@" ///
+ /// Test property comment
+ /// ";
+ var generatedCode = GenerateCode(source);
+ StringAssert.Contains(propertyComment, generatedCode);
+ StringAssert.Contains(property2Comment, generatedCode);
+ StringAssert.Contains(commandComment, generatedCode);
+ StringAssert.DoesNotContain("Ignorable comment", generatedCode);
+ StringAssert.DoesNotContain("Ordinary comment", generatedCode);
+ }
+ [Test]
+ public void GeneratePropertyName_() {
+ var source = @"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+
+ namespace Test {
+ [GenerateViewModel]
+ partial class Example {
+ [GenerateProperty]
+ int _;
+ }
+ }
+ ";
+ Assert.DoesNotThrow(() => GenerateCode(source));
+ }
+
+ static string GenerateCode(string source) {
+ return GeneratorHelper.GenerateCode(source, typeof(RelayCommand));
+ }
+ [Test]
+ public void FormattingTest() {
+ const string source =
+@"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using System.Threading.Tasks;
+using System;
+
+namespace Test {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ partial class Example0 {
+ [GenerateProperty]
+ int _Int;
+
+ [GenerateProperty(OnChangedMethod = ""OnStrChanged_"", OnChangingMethod = ""OnStrChanging_"")]
+ string _Str;
+ void OnStrChanged_() { }
+ void OnStrChanging_(string newValue) { }
+
+ ///
+ /// Test property comment
+ ///
+ [GenerateProperty]
+ [System.ComponentModel.DataAnnotations.Required]
+ [System.ComponentModel.DataAnnotations.Key]
+ long _Long;
+ void OnLongChanged(long oldValue) { }
+
+ [GenerateProperty]
+ DateTime _DateTime;
+ void OnDateTimeChanging() { }
+
+ [GenerateProperty(IsVirtual = true, SetterAccessModifier = AccessModifier.Protected)]
+ double _Double;
+
+ [GenerateProperty]
+ int _;
+
+ ///
+ /// Test command comment
+ ///
+ [GenerateCommand]
+ public void Command1(int? arg) { }
+ bool CanCommand1(int? arg) => true;
+
+ [GenerateCommand(Name = ""SomeCommand"")]
+ public Task Command2() => null;
+ bool CanCommand2(int arg) => true;
+
+ [GenerateCommand(CanExecuteMethod = ""CanCommand3_"")]
+ public void Command3(int? arg) { }
+ bool CanCommand3_(int? arg) => true;
+
+ [GenerateProperty]
+ bool a, b;
+
+ void OnCleanup() { }
+ }
+ }";
+ const string expected =
+@"using System.Collections.Generic;
+using System.ComponentModel;
+using Microsoft.Toolkit.Mvvm;
+using Microsoft.Toolkit.Mvvm.Input;
+
+#nullable enable
+
+namespace Test {
+ partial class Example0 : INotifyPropertyChanged, INotifyPropertyChanging {
+ public event PropertyChangedEventHandler? PropertyChanged;
+ public event PropertyChangingEventHandler? PropertyChanging;
+
+ protected void OnPropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);
+ protected void OnPropertyChanging(PropertyChangingEventArgs e) => PropertyChanging?.Invoke(this, e);
+
+ public int Int {
+ get => _Int;
+ set {
+ if(EqualityComparer.Default.Equals(_Int, value)) return;
+ OnPropertyChanging(IntChangingEventArgs);
+ _Int = value;
+ OnPropertyChanged(IntChangedEventArgs);
+ }
+ }
+ public string? Str {
+ get => _Str;
+ set {
+ if(EqualityComparer.Default.Equals(_Str, value)) return;
+ OnPropertyChanging(StrChangingEventArgs);
+ OnStrChanging_(value);
+ _Str = value;
+ OnPropertyChanged(StrChangedEventArgs);
+ OnStrChanged_();
+ }
+ }
+ ///
+ /// Test property comment
+ ///
+ [System.ComponentModel.DataAnnotations.RequiredAttribute]
+ [System.ComponentModel.DataAnnotations.KeyAttribute]
+ public long Long {
+ get => _Long;
+ set {
+ if(EqualityComparer.Default.Equals(_Long, value)) return;
+ OnPropertyChanging(LongChangingEventArgs);
+ var oldValue = _Long;
+ _Long = value;
+ OnPropertyChanged(LongChangedEventArgs);
+ OnLongChanged(oldValue);
+ }
+ }
+ public System.DateTime DateTime {
+ get => _DateTime;
+ set {
+ if(EqualityComparer.Default.Equals(_DateTime, value)) return;
+ OnPropertyChanging(DateTimeChangingEventArgs);
+ OnDateTimeChanging();
+ _DateTime = value;
+ OnPropertyChanged(DateTimeChangedEventArgs);
+ }
+ }
+ public virtual double Double {
+ get => _Double;
+ protected set {
+ if(EqualityComparer.Default.Equals(_Double, value)) return;
+ OnPropertyChanging(DoubleChangingEventArgs);
+ _Double = value;
+ OnPropertyChanged(DoubleChangedEventArgs);
+ }
+ }
+ public bool A {
+ get => a;
+ set {
+ if(EqualityComparer.Default.Equals(a, value)) return;
+ OnPropertyChanging(AChangingEventArgs);
+ a = value;
+ OnPropertyChanged(AChangedEventArgs);
+ }
+ }
+ public bool B {
+ get => b;
+ set {
+ if(EqualityComparer.Default.Equals(b, value)) return;
+ OnPropertyChanging(BChangingEventArgs);
+ b = value;
+ OnPropertyChanged(BChangedEventArgs);
+ }
+ }
+ RelayCommand? command1Command;
+ ///
+ /// Test command comment
+ ///
+ public RelayCommand Command1Command => command1Command ??= new RelayCommand(Command1, CanCommand1);
+ RelayCommand? someCommand;
+ public RelayCommand SomeCommand => someCommand ??= new RelayCommand(async () => await Command2());
+ RelayCommand? command3Command;
+ public RelayCommand Command3Command => command3Command ??= new RelayCommand(Command3, CanCommand3_);
+ static PropertyChangedEventArgs IntChangedEventArgs = new PropertyChangedEventArgs(nameof(Int));
+ static PropertyChangedEventArgs StrChangedEventArgs = new PropertyChangedEventArgs(nameof(Str));
+ static PropertyChangedEventArgs LongChangedEventArgs = new PropertyChangedEventArgs(nameof(Long));
+ static PropertyChangedEventArgs DateTimeChangedEventArgs = new PropertyChangedEventArgs(nameof(DateTime));
+ static PropertyChangedEventArgs DoubleChangedEventArgs = new PropertyChangedEventArgs(nameof(Double));
+ static PropertyChangedEventArgs AChangedEventArgs = new PropertyChangedEventArgs(nameof(A));
+ static PropertyChangedEventArgs BChangedEventArgs = new PropertyChangedEventArgs(nameof(B));
+ static PropertyChangingEventArgs IntChangingEventArgs = new PropertyChangingEventArgs(nameof(Int));
+ static PropertyChangingEventArgs StrChangingEventArgs = new PropertyChangingEventArgs(nameof(Str));
+ static PropertyChangingEventArgs LongChangingEventArgs = new PropertyChangingEventArgs(nameof(Long));
+ static PropertyChangingEventArgs DateTimeChangingEventArgs = new PropertyChangingEventArgs(nameof(DateTime));
+ static PropertyChangingEventArgs DoubleChangingEventArgs = new PropertyChangingEventArgs(nameof(Double));
+ static PropertyChangingEventArgs AChangingEventArgs = new PropertyChangingEventArgs(nameof(A));
+ static PropertyChangingEventArgs BChangingEventArgs = new PropertyChangingEventArgs(nameof(B));
+ }
+}
+";
+ string generatedCode = GenerateCode(source);
+ Assert.AreEqual(expected, generatedCode);
+
+ }
+ [Test]
+ public void PrivateInSealedClass() {
+ const string source =
+@"using DevExpress.Mvvm.CodeGenerators.MvvmToolkit;
+using Microsoft.Toolkit.Mvvm;
+
+namespace Test {
+ [GenerateViewModel(ImplementINotifyPropertyChanging = true)]
+ sealed partial class SealdClass {
+ [GenerateProperty]
+ string str;
+ [GenerateCommand]
+ public void Command1(int arg) { }
+ }
+}";
+ var generated = GenerateCode(source);
+ StringAssert.DoesNotContain("protected", generated);
+ }
+ }
+}
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsPrism.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsPrism.cs
index a1cd30c..b2c70f3 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsPrism.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GenearationTests/GenerationTestsPrism.cs
@@ -4,6 +4,7 @@
using System;
using Prism.Commands;
using DevExpress.Mvvm.CodeGenerators;
+using DevExpress.Mvvm.CodeGenerators.Tests;
namespace Prism.Mvvm.Tests {
[TestFixture]
@@ -51,7 +52,7 @@ public static void Main(string[] args) { }
}
[Test]
- public void PrismUsing_Command() {
+ public void Using_Command() {
var source = @"
using DevExpress.Mvvm.CodeGenerators.Prism;
namespace Test {
@@ -139,26 +140,7 @@ partial class Example {
}
static string GenerateCode(string source) {
- var references = new[] {
- MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
- MetadataReference.CreateFromFile(typeof(DelegateCommand).Assembly.Location),
- };
- Compilation inputCompilation = CSharpCompilation.Create("MyCompilation",
- new[] { CSharpSyntaxTree.ParseText(source) },
- references,
- new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- ViewModelGenerator generator = new ViewModelGenerator();
-
- GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
- driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
-
- GeneratorDriverRunResult runResult = driver.GetRunResult();
- GeneratorRunResult generatorResult = runResult.Results[0];
-
- var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString();
- return generatedCode;
+ return GeneratorHelper.GenerateCode(source, typeof(DelegateCommand));
}
[Test]
public void FormattingTest() {
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GeneratorHelper.cs b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GeneratorHelper.cs
new file mode 100644
index 0000000..5598616
--- /dev/null
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/GeneratorHelper.cs
@@ -0,0 +1,47 @@
+using DevExpress.Mvvm.Native;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace DevExpress.Mvvm.CodeGenerators.Tests {
+ public static class GeneratorHelper {
+ public static string GenerateCode(string source, Type frameworkType) {
+ Compilation inputCompilation = CreateCompilation(source, frameworkType.YieldIfNotNull().Concat(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Yield()));
+ ViewModelGenerator generator = new ViewModelGenerator();
+
+ GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
+ driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+
+ GeneratorDriverRunResult runResult = driver.GetRunResult();
+ GeneratorRunResult generatorResult = runResult.Results[0];
+
+ var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString();
+ return generatedCode;
+ }
+
+ public static Compilation CreateCompilation(string source, IEnumerable types) {
+ IEnumerable baseTypes = new[] {
+ typeof(System.Windows.Input.ICommand),
+ typeof(object),
+ }.Concat(types);
+ Compilation inputCompilation = CSharpCompilation.Create(
+ "MyCompilation",
+ new[] { CSharpSyntaxTree.ParseText(source) },
+ baseTypes.Select(x => MetadataReference.CreateFromFile(x.Assembly.Location)),
+ new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
+ );
+ return inputCompilation;
+ }
+
+ public static (IEnumerable, ImmutableArray) GetDiagnostics(Compilation inputCompilation) {
+ ViewModelGenerator generator = new ViewModelGenerator();
+ GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
+ _ = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
+ return (outputCompilation.SyntaxTrees, diagnostics);
+ }
+ }
+}
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/UnitTests.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/UnitTests.csproj
index d646db0..c03205a 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/UnitTests.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/UnitTests/UnitTests.csproj
@@ -6,7 +6,7 @@
9
true
- 8618,8604
+ true
true
@@ -15,6 +15,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/WinUITest/WinUITests.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/WinUITest/WinUITests.csproj
index d220bc7..45e0b65 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/WinUITest/WinUITests.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/WinUITest/WinUITests.csproj
@@ -6,7 +6,8 @@
DevExpress.Mvvm.CodeGenerators.WinUITests
9
true
- 8618,8604
+ True
+ 0105
WINUI
@@ -15,11 +16,12 @@
- ..\..\..\2022.1\Bin\WinUI\Sdk\Mvvm\DevExpress.WinUI.Mvvm.v22.1.dll
+ ..\..\..\..\2022.1\Bin\WinUI\Sdk\Mvvm\DevExpress.WinUI.Mvvm.v22.1.dll
+
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/PropertyGenerationTests.cs b/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/PropertyGenerationTests.cs
index 713f381..631695c 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/PropertyGenerationTests.cs
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/PropertyGenerationTests.cs
@@ -11,6 +11,10 @@ partial class GlobalClass {
namespace DevExpress.Mvvm.CodeGenerators.Tests {
class ImplementedINPCingClass : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
+ public ImplementedINPCingClass() {
+ //avoid warnings
+ PropertyChanged?.Invoke(null, null);
+ }
public int B { get; set; }
protected void RaisePropertyChanging(PropertyChangingEventArgs e) => B = 1;
protected void RaisePropertyChanging(string e) => B = 1;
@@ -141,8 +145,10 @@ void OnNonNullableIntChanging(int? newValue) =>
NonNullableIntNewValue = newValue;
#nullable disable
+#pragma warning disable DXCG1001
[GenerateProperty(OnChangedMethod = "OnChanged", OnChangingMethod = "OnChanging")]
int noParameter;
+#pragma warning restore DXCG1001
public bool ChangedMethodVisited;
public bool ChangingMethodVisited;
diff --git a/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/WithoutMvvm.csproj b/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/WithoutMvvm.csproj
index 283b458..8b10802 100644
--- a/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/WithoutMvvm.csproj
+++ b/DevExpress.Mvvm.CodeGenerators.Tests/WithoutMvvm/WithoutMvvm.csproj
@@ -5,6 +5,7 @@
false
9
true
+ True
diff --git a/DevExpress.Mvvm.CodeGenerators/AnalyzerReleasesTracking/AnalyzerReleases.Shipped.md b/DevExpress.Mvvm.CodeGenerators/AnalyzerReleasesTracking/AnalyzerReleases.Shipped.md
index 15765c4..7da9dc6 100644
--- a/DevExpress.Mvvm.CodeGenerators/AnalyzerReleasesTracking/AnalyzerReleases.Shipped.md
+++ b/DevExpress.Mvvm.CodeGenerators/AnalyzerReleasesTracking/AnalyzerReleases.Shipped.md
@@ -37,3 +37,12 @@ DXCG0011 | DevExpress.Mvvm.CodeGenerators | error | Method has Non-Nullable Argu
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------
DXCG0003 | DevExpress.Mvvm.CodeGenerators | error | Cannot find the DevExpress.Mvvm assembly
+
+## Release 21.2.2
+
+### New Rules
+Rule ID | Category | Severity | Notes
+--------|----------|----------|--------------------
+DXCG0012 | DevExpress.Mvvm.CodeGenerators | error | Cannot find OnPropertyChanged methods
+DXCG0013 | DevExpress.Mvvm.CodeGenerators | error | Class should be inherited from the ObservableRecipient class
+DXCG0014 | DevExpress.Mvvm.CodeGenerators | error | Class should be inherited from the ObservableValidator class
\ No newline at end of file
diff --git a/DevExpress.Mvvm.CodeGenerators/Diagnostics/ConstExpressions.cs b/DevExpress.Mvvm.CodeGenerators/Diagnostics/ConstExpressions.cs
index 63c2419..f88c7f0 100644
--- a/DevExpress.Mvvm.CodeGenerators/Diagnostics/ConstExpressions.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Diagnostics/ConstExpressions.cs
@@ -36,10 +36,6 @@ static partial class GeneratorDiagnostics {
const string raiseMethodNotFoundTitle = "Cannot find Raise methods";
const string raiseMethodNotFoundMessageFormat = "Cannot find the 'void RaisePropertyChang{0}(PropertyChang{0}EventArgs)' or 'void RaisePropertyChang{0}(string)' methods";
- const string genericViewModelId = idPrefix + "0009";
- const string genericViewModelTitle = "Cannot generate the generic View Model";
- const string genericViewModelMessageFormat = "The '{0}' class must be non-generic";
-
const string twoSuitableMethodsId = idPrefix + "1001";
const string twoSuitableMethodsTitle = "The class contains two suitable methods";
const string twoSuitableMethodsMessageFormat = "The '{0}' contains two suitable methods: 'void {1}()' and 'void {1}({2})'. 'void {1}({2})' is used.";
@@ -51,5 +47,17 @@ static partial class GeneratorDiagnostics {
const string nonNullableDelegateCommandArgumentId = idPrefix + "0011";
const string nonNullableDelegateCommandArgumentTitle = "Non Nullable DelegateCommand Argument";
const string nonNullableDelegateCommandArgumentMessageFormat = "The {0} method parameter cannot be of value types (int, double, bool, etc). Use the Nullable parameter instead.";
+
+ const string onMethodNotFoundId = idPrefix + "0012";
+ const string onMethodNotFoundTitle = "Cannot find OnPropertyChanged methods";
+ const string onMethodNotFoundMessageFormat = "Cannot find the 'void OnPropertyChang{0}(PropertyChang{0}EventArgs)' or 'void OnPropertyChang{0}(string)' methods";
+
+ const string noBaseObservableRecipientClassId = idPrefix + "0013";
+ const string noBaseObservableRecipientClassTitle = "Class should be inherited from the ObservableRecipient class";
+ const string noBaseObservableRecipientClassMessageFormat = "Inherit from the 'ObservableRecipient' class to use the 'Broadcast=true' option in the '{0}' property";
+
+ const string noBaseObservableValidatorClassId = idPrefix + "0014";
+ const string noBaseObservableValidatorClassTitle = "Class should be inherited from the ObservableValidator class";
+ const string noBaseObservableValidatorClassMessageFormat = "Inherit from the 'ObservableValidator' class to use the 'Validate=true' option in the '{0}' property";
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators/Diagnostics/GeneratorDiagnostics.cs b/DevExpress.Mvvm.CodeGenerators/Diagnostics/GeneratorDiagnostics.cs
index 293b2e6..5093237 100644
--- a/DevExpress.Mvvm.CodeGenerators/Diagnostics/GeneratorDiagnostics.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Diagnostics/GeneratorDiagnostics.cs
@@ -11,9 +11,12 @@ public static partial class GeneratorDiagnostics {
public static readonly DiagnosticDescriptor IncorrectCommandSignature = CreateDiagnosticDescriptor(incorrectCommandSignatureId, incorrectCommandSignatureTitle, incorrectCommandSignatureMessageFormat);
public static readonly DiagnosticDescriptor CanExecuteMethodNotFound = CreateDiagnosticDescriptor(canExecuteMethodNotFoundId, canExecuteMethodNotFoundTitle, canExecuteMethodNotFoundMessageFormat);
public static readonly DiagnosticDescriptor RaiseMethodNotFound = CreateDiagnosticDescriptor(raiseMethodNotFoundId, raiseMethodNotFoundTitle, raiseMethodNotFoundMessageFormat);
+ public static readonly DiagnosticDescriptor OnMethodNotFound = CreateDiagnosticDescriptor(onMethodNotFoundId, onMethodNotFoundTitle, onMethodNotFoundMessageFormat);
public static readonly DiagnosticDescriptor TwoSuitableMethods = CreateDiagnosticDescriptor(twoSuitableMethodsId, twoSuitableMethodsTitle, twoSuitableMethodsMessageFormat, DiagnosticSeverity.Warning);
public static readonly DiagnosticDescriptor MoreThanOneGenerateViewModelAttributes = CreateDiagnosticDescriptor(moreThanOneGenerateViewModelAttributesId, moreThanOneGenerateViewModelAttributesTitle, moreThanOneGenerateViewModelAttributesMessageFormat);
public static readonly DiagnosticDescriptor NonNullableDelegateCommandArgument = CreateDiagnosticDescriptor(nonNullableDelegateCommandArgumentId, nonNullableDelegateCommandArgumentTitle, nonNullableDelegateCommandArgumentMessageFormat);
+ public static readonly DiagnosticDescriptor NoBaseObservableRecipientClass = CreateDiagnosticDescriptor(noBaseObservableRecipientClassId, noBaseObservableRecipientClassTitle, noBaseObservableRecipientClassMessageFormat);
+ public static readonly DiagnosticDescriptor NoBaseObservableValidatorClass = CreateDiagnosticDescriptor(noBaseObservableValidatorClassId, noBaseObservableValidatorClassTitle, noBaseObservableValidatorClassMessageFormat);
public static void ReportNoPartialModifier(this GeneratorExecutionContext context, INamedTypeSymbol classSymbol) =>
context.ReportDiagnostic(NoPartialModifier, SymbolNameLocation(classSymbol), classSymbol.Name);
@@ -25,8 +28,13 @@ public static void ReportIncorrectCommandSignature(this GeneratorExecutionContex
context.ReportDiagnostic(IncorrectCommandSignature, SymbolNameLocation(methodSymbol), methodSymbol.ReturnType.ToDisplayStringNullable(), methodSymbol.Name, ParameterTypesToDisplayString(methodSymbol));
public static void ReportCanExecuteMethodNotFound(this GeneratorExecutionContext context, IMethodSymbol methodSymbol, string canExecuteMethodName, string parameterType, IEnumerable candidates) =>
context.ReportDiagnostic(CanExecuteMethodNotFound, SymbolNameLocation(methodSymbol, AttributesGenerator.CanExecuteMethod), canExecuteMethodName, parameterType, CandidatesMessage(candidates));
- public static void ReportRaiseMethodNotFound(this GeneratorExecutionContext context, INamedTypeSymbol classSymbol, string end) =>
- context.ReportDiagnostic(RaiseMethodNotFound, SymbolNameLocation(classSymbol), end);
+ internal static void ReportRaiseMethodNotFound(this GeneratorExecutionContext context, INamedTypeSymbol classSymbol, string end, RaiseMethodPrefix prefix) {
+ if(prefix == RaiseMethodPrefix.Raise)
+ context.ReportDiagnostic(RaiseMethodNotFound, SymbolNameLocation(classSymbol), end);
+ else
+ context.ReportDiagnostic(OnMethodNotFound, SymbolNameLocation(classSymbol), end);
+ }
+
public static void ReportTwoSuitableMethods(this GeneratorExecutionContext context, INamedTypeSymbol classSymbol, IFieldSymbol fieldSymbol, string methodName, string parameterType) =>
context.ReportDiagnostic(TwoSuitableMethods, SymbolNameLocation(fieldSymbol), classSymbol.Name, methodName, parameterType);
public static void ReportMoreThanOneGenerateViewModelAttributes(this GeneratorExecutionContext context, INamedTypeSymbol classSymbol) =>
@@ -34,6 +42,11 @@ public static void ReportMoreThanOneGenerateViewModelAttributes(this GeneratorEx
public static void ReportNonNullableDelegateCommandArgument(this GeneratorExecutionContext context, IMethodSymbol methodSymbol) =>
context.ReportDiagnostic(NonNullableDelegateCommandArgument, SymbolNameLocation(methodSymbol), methodSymbol.Name);
+ public static void ReportNoBaseObservableRecipientClass(this GeneratorExecutionContext context, IFieldSymbol fieldSymbol, string propertyName) =>
+ context.ReportDiagnostic(NoBaseObservableRecipientClass, SymbolNameLocation(fieldSymbol), propertyName);
+ public static void ReportNoBaseObservableValidatorClass(this GeneratorExecutionContext context, IFieldSymbol fieldSymbol, string propertyName) =>
+ context.ReportDiagnostic(NoBaseObservableValidatorClass, SymbolNameLocation(fieldSymbol), propertyName);
+
static void ReportDiagnostic(this GeneratorExecutionContext context, DiagnosticDescriptor descriptor, Location location, params object[] messageArgs) =>
context.ReportDiagnostic(Diagnostic.Create(descriptor, location, messageArgs));
static DiagnosticDescriptor CreateDiagnosticDescriptor(string id, string title, string messageFormat, DiagnosticSeverity diagnosticSeverity = DiagnosticSeverity.Error) =>
diff --git a/DevExpress.Mvvm.CodeGenerators/ExtensionMethods.cs b/DevExpress.Mvvm.CodeGenerators/ExtensionMethods.cs
index 5717d74..9a2e10f 100644
--- a/DevExpress.Mvvm.CodeGenerators/ExtensionMethods.cs
+++ b/DevExpress.Mvvm.CodeGenerators/ExtensionMethods.cs
@@ -16,6 +16,12 @@ static NullableFlowState ToNullableFlowState(NullableAnnotation nullableAnnotati
NullableAnnotation.Annotated => NullableFlowState.MaybeNull,
_ => NullableFlowState.None
};
+ public static IEnumerable GetParents(this INamedTypeSymbol typeSymbol) {
+ for(INamedTypeSymbol parent = typeSymbol.BaseType!; parent != null; parent = parent.BaseType!) {
+ yield return parent;
+ }
+ }
+
#endregion
#region String
@@ -25,5 +31,21 @@ static NullableFlowState ToNullableFlowState(NullableAnnotation nullableAnnotati
public static string TypeToString(this TypeKind type) => type == TypeKind.Structure ? "struct" : type.ToString().ToLower();
public static string BoolToStringValue(this bool val) => val ? "true" : "false";
+
+ internal static string ToStringValue(this RaiseMethodPrefix val) {
+ return val switch {
+ RaiseMethodPrefix.On => "On",
+ RaiseMethodPrefix.Raise => "Raise",
+ _ => throw new InvalidOperationException(),
+ };
+ }
+
+ internal static RaiseMethodPrefix GetRasiePrefix(this SupportedMvvm mvvm) {
+ return mvvm switch {
+ SupportedMvvm.None or SupportedMvvm.Dx or SupportedMvvm.Prism or SupportedMvvm.MvvmLight => RaiseMethodPrefix.Raise,
+ SupportedMvvm.MvvmToolkit => RaiseMethodPrefix.On,
+ _ => throw new InvalidOperationException()
+ };
+ }
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators/Generators/ClassGenerator.cs b/DevExpress.Mvvm.CodeGenerators/Generators/ClassGenerator.cs
index d81b909..a3a4da9 100644
--- a/DevExpress.Mvvm.CodeGenerators/Generators/ClassGenerator.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Generators/ClassGenerator.cs
@@ -6,6 +6,16 @@
namespace DevExpress.Mvvm.CodeGenerators {
enum ChangeEventRaiseMode { EventArgs, PropertyName }
+ enum RaiseMethodPrefix { On, Raise }
+ struct RaiseInfo {
+ public readonly ChangeEventRaiseMode Mode;
+ public readonly RaiseMethodPrefix Prefix;
+ public RaiseInfo(ChangeEventRaiseMode mode, RaiseMethodPrefix prefix) {
+ Mode = mode;
+ Prefix = prefix;
+ }
+ }
+
static class ClassGenerator {
const string defaultUsings =
@"using System.Collections.Generic;
@@ -43,8 +53,8 @@ public static void GenerateSourceCode(SourceBuilder source, ContextInfo contextI
genericTypes, outerClasses, mvvm, contextInfo.Compilation);
- bool needStaticChangedEventArgs = inpcedInfo.HasRaiseMethodWithEventArgsParameter || impelementRaiseChangedMethod;
- bool needStaticChangingEventArgs = inpcingInfo.HasAttribute && (inpcingInfo.HasRaiseMethodWithEventArgsParameter || impelementRaiseChangingMethod);
+ bool needStaticChangedEventArgs = inpcedInfo.HasMethodWithEventArgsPrefix || impelementRaiseChangedMethod;
+ bool needStaticChangingEventArgs = inpcingInfo.HasAttribute && (inpcingInfo.HasMethodWithEventArgsPrefix || impelementRaiseChangingMethod);
IReadOnlyList propertyNames = GenerateProperties(source, contextInfo, classSymbol, inpcedInfo, inpcingInfo, needStaticChangedEventArgs, needStaticChangingEventArgs, mvvm);
GenerateCommands(source, contextInfo, classSymbol, mvvm);
@@ -70,6 +80,9 @@ static SourceBuilder GenerateHeader(ContextInfo contextInfo, SourceBuilder sourc
source.AppendLine("using GalaSoft.MvvmLight.Command;");
source.AppendLine("using GalaSoft.MvvmLight.Messaging;");
break;
+ case SupportedMvvm.MvvmToolkit:
+ source.AppendLine("using Microsoft.Toolkit.Mvvm;").AppendLine("using Microsoft.Toolkit.Mvvm.Input;");
+ break;
case SupportedMvvm.None:
break;
default:
@@ -123,31 +136,24 @@ static void AppendGenericArguments(SourceBuilder source, List gener
}
}
static IReadOnlyList GenerateProperties(SourceBuilder source, ContextInfo contextInfo, INamedTypeSymbol classSymbol, INPCInfo inpcedInfo, INPCInfo inpcingInfo, bool needStaticChangedEventArgs, bool needStaticChangingEventArgs, SupportedMvvm mvvm) {
- ChangeEventRaiseMode? changedRaiseMode = needStaticChangedEventArgs
- ? ChangeEventRaiseMode.EventArgs
- : inpcedInfo.HasRaiseMethodWithStringParameter
- ? ChangeEventRaiseMode.PropertyName
- : default(ChangeEventRaiseMode?);
- ChangeEventRaiseMode? changingRaiseMode = needStaticChangingEventArgs
- ? ChangeEventRaiseMode.EventArgs
- : inpcingInfo.HasAttribute && inpcingInfo.HasRaiseMethodWithStringParameter
- ? ChangeEventRaiseMode.PropertyName
- : default(ChangeEventRaiseMode?);
+ RaiseMethodPrefix prefix = mvvm.GetRasiePrefix();
+ RaiseInfo? changedInfo = GetRaiseInfo(inpcedInfo, needStaticChangedEventArgs, true, prefix);
+ RaiseInfo? changingInfo = GetRaiseInfo(inpcingInfo, needStaticChangingEventArgs, inpcingInfo.HasAttribute, prefix);
bool generateProperties = true;
List propertyNames = new();
IEnumerable fieldCandidates = ClassHelper.GetFieldCandidates(classSymbol, contextInfo.GetFrameworkAttributes(mvvm).PropertyAttributeSymbol);
if(fieldCandidates.Any()) {
- if(changedRaiseMode == null) {
- contextInfo.Context.ReportRaiseMethodNotFound(classSymbol, "ed");
+ if(changedInfo == null) {
+ contextInfo.Context.ReportRaiseMethodNotFound(classSymbol, "ed", prefix);
generateProperties = false;
}
- if(inpcingInfo.HasAttribute && changingRaiseMode == null) {
- contextInfo.Context.ReportRaiseMethodNotFound(classSymbol, "ing");
+ if(inpcingInfo.HasAttribute && changingInfo == null) {
+ contextInfo.Context.ReportRaiseMethodNotFound(classSymbol, "ing", prefix);
generateProperties = false;
}
if(generateProperties)
foreach(IFieldSymbol fieldSymbol in fieldCandidates) {
- string? propertyName = PropertyGenerator.Generate(source, contextInfo, classSymbol, fieldSymbol, changedRaiseMode, changingRaiseMode, mvvm);
+ string? propertyName = PropertyGenerator.Generate(source, contextInfo, classSymbol, fieldSymbol, changedInfo, changingInfo, mvvm);
if(propertyName != null) {
propertyNames.Add(propertyName);
}
@@ -156,6 +162,14 @@ static IReadOnlyList GenerateProperties(SourceBuilder source, ContextInf
return propertyNames;
}
+ private static RaiseInfo? GetRaiseInfo(INPCInfo inpcingInfo, bool needStaticChangingEventArgs, bool hasAttribute, RaiseMethodPrefix prefix) {
+ return needStaticChangingEventArgs
+ ? new RaiseInfo(ChangeEventRaiseMode.EventArgs, prefix)
+ : hasAttribute && inpcingInfo.HasMethodWithStringPrefix
+ ? new RaiseInfo(ChangeEventRaiseMode.PropertyName, prefix)
+ : default(RaiseInfo?);
+ }
+
static void GenerateCommands(SourceBuilder source, ContextInfo contextInfo, INamedTypeSymbol classSymbol, SupportedMvvm mvvm) {
IEnumerable commandCandidates = ClassHelper.GetCommandCandidates(classSymbol, contextInfo.GetFrameworkAttributes(mvvm).CommandAttributeSymbol);
foreach(IMethodSymbol methodSymbol in commandCandidates) {
@@ -168,19 +182,21 @@ static void AddAvailableInterfaces(List interfaces, Context
case SupportedMvvm.Dx:
if(ClassHelper.GetImplementIDEIValue(contextInfo, classSymbol) && !ClassHelper.IsInterfaceImplementedInCurrentClass(classSymbol, contextInfo.Dx!.IDEISymbol))
interfaces.Add(new IDataErrorInfoGenerator());
- if(ClassHelper.GetImplementISPVMValue(contextInfo, classSymbol, mvvm) && !ClassHelper.IsInterfaceImplemented(classSymbol, contextInfo.Dx!.ISPVMSymbol, contextInfo, mvvm))
+ if(ClassHelper.ShouldImplementInterface(classSymbol, contextInfo.Dx!.ISPVMSymbol, contextInfo, mvvm, (context, type) => ClassHelper.GetImplementISPVMValue(context, type, mvvm)))
interfaces.Add(new ISupportParentViewModelGenerator(ClassHelper.ContainsOnChangedMethod(classSymbol, "OnParentViewModelChanged", 1, "object")));
if(ClassHelper.GetImplementISSValue(contextInfo, classSymbol) && !ClassHelper.IsInterfaceImplementedInCurrentClass(classSymbol, contextInfo.Dx!.ISSSymbol))
interfaces.Add(new ISupportServicesGenerator(classSymbol.IsSealed, contextInfo.IsWinUI));
break;
case SupportedMvvm.Prism:
- if(ClassHelper.GetImplementIAAValue(contextInfo, classSymbol) && !ClassHelper.IsInterfaceImplemented(classSymbol, contextInfo.Prism!.IAASymbol, contextInfo, mvvm))
+ if(ClassHelper.ShouldImplementInterface(classSymbol, contextInfo.Prism!.IAASymbol, contextInfo, mvvm, ClassHelper.GetImplementIAAValue))
interfaces.Add(new IActiveAwareGenerator(ClassHelper.ContainsOnChangedMethod(classSymbol, "OnIsActiveChanged", 0, null)));
break;
case SupportedMvvm.MvvmLight:
- if(ClassHelper.GetImplementICUValue(contextInfo, classSymbol) && !ClassHelper.IsInterfaceImplemented(classSymbol, contextInfo.MvvmLight!.ICUSymbol, contextInfo, mvvm))
+ if(ClassHelper.ShouldImplementInterface(classSymbol, contextInfo.MvvmLight!.ICUSymbol, contextInfo, mvvm, ClassHelper.GetImplementICUValue))
interfaces.Add(new ICleanupGenerator(ClassHelper.ContainsOnChangedMethod(classSymbol, "OnCleanup", 0, null), classSymbol.IsSealed));
break;
+ case SupportedMvvm.MvvmToolkit:
+ break;
case SupportedMvvm.None:
break;
default:
diff --git a/DevExpress.Mvvm.CodeGenerators/Generators/CommandGenerator.cs b/DevExpress.Mvvm.CodeGenerators/Generators/CommandGenerator.cs
index aed8c0a..bf0066d 100644
--- a/DevExpress.Mvvm.CodeGenerators/Generators/CommandGenerator.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Generators/CommandGenerator.cs
@@ -69,15 +69,15 @@ public static void Generate(SourceBuilder source, ContextInfo info, INamedTypeSy
string[] observesProperties = CommandHelper.GetObservesProperties(methodSymbol, commandAttribute);
AppendGetterPrism(source, info, methodSymbol, mvvm, isCommand, canExecuteMethodName, genericArgumentType, name, observesCanExecuteProperty, observesProperties);
break;
- case SupportedMvvm.MvvmLight:
- AppendGetterMvvmLight(source, info, methodSymbol, mvvm, isCommand, canExecuteMethodName, genericArgumentType, name);
+ case SupportedMvvm.MvvmLight or SupportedMvvm.MvvmToolkit:
+ AppendGetterRelayCommand(source, info, methodSymbol, mvvm, isCommand, canExecuteMethodName, genericArgumentType, name);
break;
default:
throw new InvalidEnumArgumentException();
}
}
- static string GetCanExecuteMethodName(ContextInfo info, INamedTypeSymbol classSymbol, IMethodSymbol methodSymbol, ITypeSymbol? parameterType, INamedTypeSymbol commandAttributeSymbol) {
+ static string? GetCanExecuteMethodName(ContextInfo info, INamedTypeSymbol classSymbol, IMethodSymbol methodSymbol, ITypeSymbol? parameterType, INamedTypeSymbol commandAttributeSymbol) {
string? canExecuteMethodName = CommandHelper.GetCanExecuteMethodName(methodSymbol, commandAttributeSymbol);
if(canExecuteMethodName == null) {
IEnumerable candidate = CommandHelper.GetCanExecuteMethodCandidates(classSymbol, "Can" + methodSymbol.Name, parameterType, info);
@@ -88,12 +88,12 @@ static string GetCanExecuteMethodName(ContextInfo info, INamedTypeSymbol classSy
info.Context.ReportCanExecuteMethodNotFound(methodSymbol, canExecuteMethodName, parameterType?.ToDisplayStringNullable() ?? string.Empty, CommandHelper.GetMethods(classSymbol, canExecuteMethodName));
}
}
- return canExecuteMethodName ?? "null";
+ return canExecuteMethodName;
}
- static void AppendGetterPrism(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string canExecuteMethodName, string genericArgumentType, string name, string observesCanExecuteProperty, string[] observesProperties) {
+ static void AppendGetterPrism(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string? canExecuteMethodName, string genericArgumentType, string name, string observesCanExecuteProperty, string[] observesProperties) {
source.AppendCommandNameWithGenericType(mvvm, isCommand, genericArgumentType, name).AppendMethodName(isCommand, methodSymbol.Name, genericArgumentType);
- if(canExecuteMethodName != "null")
+ if(canExecuteMethodName != null)
source.Append(", ").Append(canExecuteMethodName);
if(!string.IsNullOrEmpty(observesCanExecuteProperty))
source.Append(").ObservesCanExecute(() => ").Append(observesCanExecuteProperty);
@@ -103,18 +103,25 @@ static void AppendGetterPrism(SourceBuilder source, ContextInfo info, IMethodSym
source.Append(").ObservesProperty(() => ").Append(property);
source.AppendLine(");");
}
- static void AppendGetterDx(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string canExecuteMethodName, string genericArgumentType, string name) {
+ static void AppendGetterDx(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string? canExecuteMethodName, string genericArgumentType, string name) {
INamedTypeSymbol commandAttribute = info.Dx!.CommandAttributeSymbol;
source.AppendCommandNameWithGenericType(mvvm, isCommand, genericArgumentType, name).Append('(');
source.AppendDxParametersList(methodSymbol, commandAttribute, canExecuteMethodName, isCommand, methodSymbol.Name, info.IsWinUI);
source.AppendLine(");");
}
- static void AppendGetterMvvmLight(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string canExecuteMethodName, string genericArgumentType, string name) {
+ static void AppendGetterRelayCommand(SourceBuilder source, ContextInfo info, IMethodSymbol methodSymbol, SupportedMvvm mvvm, bool isCommand, string? canExecuteMethodName, string genericArgumentType, string name) {
source.AppendCommandNameWithGenericType(mvvm, isCommand, genericArgumentType, name).AppendMethodName(isCommand, methodSymbol.Name, genericArgumentType);
- source.Append(", ").Append(canExecuteMethodName).AppendLine(");");
+ if(mvvm == SupportedMvvm.MvvmLight) {
+ source.Append(", ");
+ source.Append(canExecuteMethodName ?? "null");
+ } else if(canExecuteMethodName != null) {
+ source.Append(", ");
+ source.Append(canExecuteMethodName);
+ }
+ source.AppendLine(");");
}
- static void AppendDxParametersList(this SourceBuilder source, IMethodSymbol methodSymbol, INamedTypeSymbol commandAttributeSymbol, string canExecuteMethodName, bool isCommand, string executeMethod, bool isWinUI) {
- source.Append(executeMethod).Append(", ").Append(canExecuteMethodName);
+ static void AppendDxParametersList(this SourceBuilder source, IMethodSymbol methodSymbol, INamedTypeSymbol commandAttributeSymbol, string? canExecuteMethodName, bool isCommand, string executeMethod, bool isWinUI) {
+ source.Append(executeMethod).Append(", ").Append(canExecuteMethodName ?? "null");
if(!isCommand) {
string allowMultipleExecution = CommandHelper.GetAllowMultipleExecutionValue(methodSymbol, commandAttributeSymbol).BoolToStringValue();
source.Append(", ").Append(allowMultipleExecution);
diff --git a/DevExpress.Mvvm.CodeGenerators/Generators/GeneratorCore.cs b/DevExpress.Mvvm.CodeGenerators/Generators/GeneratorCore.cs
index aa63bbb..c3ed6c2 100644
--- a/DevExpress.Mvvm.CodeGenerators/Generators/GeneratorCore.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Generators/GeneratorCore.cs
@@ -40,11 +40,13 @@ public static void Execute(GeneratorExecutionContext context) {
bool hasDxAttribute = AttributeHelper.HasAttribute(classSymbol, contextInfo.Dx?.ViewModelAttributeSymbol);
bool hasPrismAttribute = AttributeHelper.HasAttribute(classSymbol, contextInfo.Prism?.ViewModelAttributeSymbol);
bool hasMvvmLightAttribute = AttributeHelper.HasAttribute(classSymbol, contextInfo.MvvmLight?.ViewModelAttributeSymbol);
+ bool hasMvvmToolkitAttribute = AttributeHelper.HasAttribute(classSymbol, contextInfo.MvvmToolkit?.ViewModelAttributeSymbol);
int mvvmCount = 0;
if(hasDxAttribute) mvvmCount++;
if(hasPrismAttribute) mvvmCount++;
if(hasMvvmLightAttribute) mvvmCount++;
+ if(hasMvvmToolkitAttribute) mvvmCount++;
if(mvvmCount > 1) {
context.ReportMoreThanOneGenerateViewModelAttributes(classSymbol);
@@ -61,6 +63,8 @@ public static void Execute(GeneratorExecutionContext context) {
mvvm = SupportedMvvm.Prism;
else if(hasMvvmLightAttribute)
mvvm = SupportedMvvm.MvvmLight;
+ else if(hasMvvmToolkitAttribute)
+ mvvm = SupportedMvvm.MvvmToolkit;
else continue;
if(processedSymbols.Contains(classSymbol))
diff --git a/DevExpress.Mvvm.CodeGenerators/Generators/PropertyGenerator.cs b/DevExpress.Mvvm.CodeGenerators/Generators/PropertyGenerator.cs
index 60c5033..c797a5d 100644
--- a/DevExpress.Mvvm.CodeGenerators/Generators/PropertyGenerator.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Generators/PropertyGenerator.cs
@@ -1,13 +1,24 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
+using System.Diagnostics;
namespace DevExpress.Mvvm.CodeGenerators {
static class PropertyGenerator {
- public static string? Generate(SourceBuilder source, ContextInfo info, INamedTypeSymbol classSymbol, IFieldSymbol fieldSymbol, ChangeEventRaiseMode? changedEventRaiseMode, ChangeEventRaiseMode? changingEventRaiseMode, SupportedMvvm mvvm) {
+ public static string? Generate(SourceBuilder source, ContextInfo info, INamedTypeSymbol classSymbol, IFieldSymbol fieldSymbol, RaiseInfo? changedInfo, RaiseInfo? changingInfo, SupportedMvvm mvvm) {
var propertyAttributeSymbol = info.GetFrameworkAttributes(mvvm).PropertyAttributeSymbol;
string propertyName = PropertyHelper.CreatePropertyName(fieldSymbol.Name);
if(propertyName == fieldSymbol.Name)
info.Context.ReportInvalidPropertyName(fieldSymbol, propertyName);
+ bool toolkitBroadcast = PropertyHelper.GetBroadcastAttributeValue(fieldSymbol, propertyAttributeSymbol);
+ if(toolkitBroadcast && !info.Compilation.HasImplicitConversion(classSymbol, info.MvvmToolkit!.ObservableRecipientSymbol)) {
+ info.Context.ReportNoBaseObservableRecipientClass(fieldSymbol, propertyName);
+ return null;
+ }
+ bool toolkitValidate = PropertyHelper.GetValidateAttributeValue(fieldSymbol, propertyAttributeSymbol);
+ if(toolkitValidate && !info.Compilation.HasImplicitConversion(classSymbol, info.MvvmToolkit!.ObservableValidatorSymbol)) {
+ info.Context.ReportNoBaseObservableValidatorClass(fieldSymbol, propertyName);
+ return null;
+ }
string? changedMethod = PropertyHelper.GetChangedMethod(info, classSymbol, fieldSymbol, propertyName, fieldSymbol.Type, mvvm);
string? changingMethod = PropertyHelper.GetChangingMethod(info, classSymbol, fieldSymbol, propertyName, fieldSymbol.Type, mvvm);
@@ -33,15 +44,23 @@ static class PropertyGenerator {
source.Tab.Append(setterAccessModifier).AppendLine("set {");
source.Tab.Tab.Append("if(EqualityComparer<").Append(typeName).Append(">.Default.Equals(").Append(fieldName).AppendLine(", value)) return;");
- AppendRaiseChangingMethod(source.Tab.Tab, changingEventRaiseMode, propertyName);
+ AppendRaiseChangeMethod(source.Tab.Tab, changingInfo, propertyName, "ing");
if(!string.IsNullOrEmpty(changingMethod))
source.Tab.Tab.AppendLine(changingMethod);
- if(!string.IsNullOrEmpty(changedMethod) && !changedMethod.EndsWith("();"))
+ if(toolkitBroadcast || toolkitValidate)
+ Debug.Assert(mvvm == SupportedMvvm.MvvmToolkit);
+
+ if(toolkitBroadcast || (!string.IsNullOrEmpty(changedMethod) && !changedMethod.EndsWith("();")))
source.Tab.Tab.Append("var oldValue = ").Append(fieldName).AppendLine(";");
source.Tab.Tab.Append(fieldName).AppendLine(" = value;");
- AppendRaiseChangedMethod(source.Tab.Tab, changedEventRaiseMode, propertyName);
+ AppendRaiseChangeMethod(source.Tab.Tab, changedInfo, propertyName, "ed");
+
+ if(toolkitBroadcast)
+ source.Tab.Tab.AppendLine($"Broadcast<{typeName}>(oldValue, value, nameof({propertyName}));");
+ if(toolkitValidate)
+ source.Tab.Tab.AppendLine($"ValidateProperty(value, nameof({propertyName}));");
if(!string.IsNullOrEmpty(changedMethod))
source.Tab.Tab.AppendLine(changedMethod);
@@ -52,18 +71,27 @@ static class PropertyGenerator {
return propertyName;
}
- static void AppendRaiseChangingMethod(SourceBuilder source, ChangeEventRaiseMode? eventRaiseMode, string propertyName) {
- if(eventRaiseMode == ChangeEventRaiseMode.EventArgs)
- source.Append("RaisePropertyChanging(").Append(propertyName).AppendLine("ChangingEventArgs);");
- if(eventRaiseMode == ChangeEventRaiseMode.PropertyName)
- source.Append("RaisePropertyChanging(nameof(").Append(propertyName).AppendLine("));");
- }
-
- static void AppendRaiseChangedMethod(SourceBuilder source, ChangeEventRaiseMode? eventRaiseMode, string propertyName) {
- if(eventRaiseMode == ChangeEventRaiseMode.EventArgs)
- source.Append("RaisePropertyChanged(").Append(propertyName).AppendLine("ChangedEventArgs);");
- if(eventRaiseMode == ChangeEventRaiseMode.PropertyName)
- source.Append("RaisePropertyChanged(nameof(").Append(propertyName).AppendLine("));");
+ static void AppendRaiseChangeMethod(SourceBuilder source, RaiseInfo? raiseInfo, string propertyName, string suffix) {
+ if(raiseInfo?.Mode == ChangeEventRaiseMode.EventArgs) {
+ source
+ .Append(raiseInfo.Value.Prefix.ToStringValue())
+ .Append("PropertyChang")
+ .Append(suffix)
+ .Append('(')
+ .Append(propertyName)
+ .Append("Chang")
+ .Append(suffix)
+ .AppendLine("EventArgs);");
+ }
+ if(raiseInfo?.Mode == ChangeEventRaiseMode.PropertyName) {
+ source
+ .Append(raiseInfo.Value.Prefix.ToStringValue())
+ .Append("PropertyChang")
+ .Append(suffix)
+ .Append("(nameof(")
+ .Append(propertyName)
+ .AppendLine("));");
+ }
}
static void AppendSetterAttribute(SourceBuilder source, ContextInfo info, IFieldSymbol fieldSymbol, string fieldName) {
diff --git a/DevExpress.Mvvm.CodeGenerators/Helpers/ClassHelper.cs b/DevExpress.Mvvm.CodeGenerators/Helpers/ClassHelper.cs
index a6d7d1e..0d87fa3 100644
--- a/DevExpress.Mvvm.CodeGenerators/Helpers/ClassHelper.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Helpers/ClassHelper.cs
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis;
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -27,18 +28,21 @@ public static IEnumerable GetCommandCandidates(INamedTypeSymbol c
GetProcessingMembers(classSymbol, commandSymbol);
public static bool IsInterfaceImplementedInCurrentClass(INamedTypeSymbol classSymbol, INamedTypeSymbol interfaceSymbol) =>
classSymbol.Interfaces.Contains(interfaceSymbol);
- public static bool IsInterfaceImplemented(INamedTypeSymbol classSymbol, INamedTypeSymbol? interfaceSymbol, ContextInfo contextInfo, SupportedMvvm mvvm) {
- if(interfaceSymbol == null)
+
+ public static bool ShouldImplementInterface(INamedTypeSymbol classSymbol, INamedTypeSymbol? interfaceSymbol, ContextInfo contextInfo, SupportedMvvm mvvm, Func getShouldImplementValue) {
+ if(!getShouldImplementValue(contextInfo, classSymbol))
return false;
- if(IsInterfaceImplementedInCurrentClass(classSymbol, interfaceSymbol))
+ if(interfaceSymbol == null)
return true;
- for(INamedTypeSymbol parent = classSymbol.BaseType!; parent != null; parent = parent.BaseType!) {
- bool hasAttribute = AttributeHelper.HasAttribute(parent, contextInfo.GetFrameworkAttributes(mvvm).ViewModelAttributeSymbol) && GetImplementISPVMValue(contextInfo, parent, mvvm);
+ if(IsInterfaceImplementedInCurrentClass(classSymbol, interfaceSymbol))
+ return false;
+ foreach(INamedTypeSymbol parent in classSymbol.GetParents()) {
+ bool hasAttribute = AttributeHelper.HasAttribute(parent, contextInfo.GetFrameworkAttributes(mvvm).ViewModelAttributeSymbol) && getShouldImplementValue(contextInfo, parent);
bool hasImplementation = IsInterfaceImplementedInCurrentClass(parent, interfaceSymbol);
if(hasAttribute || hasImplementation)
- return true;
+ return false;
}
- return false;
+ return true;
}
static IEnumerable GetProcessingMembers(INamedTypeSymbol classSymbol, INamedTypeSymbol attributeSymbol) where T : ISymbol =>
diff --git a/DevExpress.Mvvm.CodeGenerators/Helpers/CommandHelper.cs b/DevExpress.Mvvm.CodeGenerators/Helpers/CommandHelper.cs
index d1b41a9..39e79e6 100644
--- a/DevExpress.Mvvm.CodeGenerators/Helpers/CommandHelper.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Helpers/CommandHelper.cs
@@ -29,7 +29,7 @@ public static SourceBuilder AppendCommandNameWithGenericType(this SourceBuilder
public static SourceBuilder AppendCommandGenericType(this SourceBuilder source, SupportedMvvm mvvm, bool isCommand, string genericArgumentType) => mvvm switch {
SupportedMvvm.Dx => source.AppendCommandGenericTypeCore(isCommand, genericArgumentType, "DelegateCommand"),
SupportedMvvm.Prism => source.AppendCommandGenericTypeCore(true, genericArgumentType, "DelegateCommand"),
- SupportedMvvm.MvvmLight => source.AppendCommandGenericTypeCore(true, genericArgumentType, "RelayCommand"),
+ SupportedMvvm.MvvmLight or SupportedMvvm.MvvmToolkit => source.AppendCommandGenericTypeCore(true, genericArgumentType, "RelayCommand"),
SupportedMvvm.None => source,
_ => throw new InvalidOperationException()
};
diff --git a/DevExpress.Mvvm.CodeGenerators/Helpers/PropertyHelper.cs b/DevExpress.Mvvm.CodeGenerators/Helpers/PropertyHelper.cs
index 8248e67..d26c7fe 100644
--- a/DevExpress.Mvvm.CodeGenerators/Helpers/PropertyHelper.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Helpers/PropertyHelper.cs
@@ -4,14 +4,9 @@
namespace DevExpress.Mvvm.CodeGenerators {
static class PropertyHelper {
- static readonly string nameofIsVirtual = AttributesGenerator.IsVirtual;
- static readonly string nameofChangedMethod = AttributesGenerator.OnChangedMethod;
- static readonly string nameofChangingMethod = AttributesGenerator.OnChangingMethod;
- static readonly string nameofSetterAccessModifier = AttributesGenerator.SetterAccessModifier;
-
public static string CreatePropertyName(string fieldName) => fieldName.TrimStart('_').FirstToUpperCase();
public static bool GetIsVirtualValue(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) =>
- AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, nameofIsVirtual, false);
+ AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.IsVirtual, false);
public static string? GetChangedMethod(ContextInfo info, INamedTypeSymbol classSymbol, IFieldSymbol fieldSymbol, string propertyName, ITypeSymbol fieldType, SupportedMvvm mvvm) {
string? methodName = GetChangedMethodName(fieldSymbol, info.GetFrameworkAttributes(mvvm).PropertyAttributeSymbol);
return GetMethod(info, classSymbol, fieldSymbol, methodName, "On" + propertyName + "Changed", "oldValue", fieldType);
@@ -21,9 +16,13 @@ public static bool GetIsVirtualValue(IFieldSymbol fieldSymbol, INamedTypeSymbol
return GetMethod(info, classSymbol, fieldSymbol, methodName, "On" + propertyName + "Changing", "value", fieldType);
}
public static string GetSetterAccessModifierValue(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) {
- int enumIndex = AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, nameofSetterAccessModifier, 0);
+ int enumIndex = AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.SetterAccessModifier, 0);
return AccessModifierGenerator.GetCodeRepresentation((AccessModifier)enumIndex);
}
+ public static bool GetBroadcastAttributeValue(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) =>
+ AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.Broadcast, false);
+ public static bool GetValidateAttributeValue(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) =>
+ AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.Validate, false);
public static NullableAnnotation GetNullableAnnotation(ITypeSymbol type) =>
type.IsReferenceType && type.NullableAnnotation == NullableAnnotation.None
? NullableAnnotation.Annotated
@@ -49,9 +48,9 @@ static string ToNotAnnotatedDisplayString(ITypeSymbol type) {
}
static string? GetChangedMethodName(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) =>
- AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, nameofChangedMethod, (string?)null);
+ AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.OnChangedMethod, (string?)null);
static string? GetChangingMethodName(IFieldSymbol fieldSymbol, INamedTypeSymbol propertySymbol) =>
- AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, nameofChangingMethod, (string?)null);
+ AttributeHelper.GetPropertyActualValue(fieldSymbol, propertySymbol, AttributesGenerator.OnChangingMethod, (string?)null);
static string? GetMethod(ContextInfo info, INamedTypeSymbol classSymbol, IFieldSymbol fieldSymbol, string? methodName, string defaultMethodName, string parameterName, ITypeSymbol fieldType) {
bool useDefaultName = false;
if(methodName == null) {
@@ -82,7 +81,8 @@ static IEnumerable GetOnChangedMethods(INamedTypeSymbol classSymb
public static bool CanAppendAttribute(string attributeName) {
return !(attributeName.StartsWith(AttributesGenerator.DxPropertyAttributeFullName!) ||
attributeName.StartsWith(AttributesGenerator.PrismPropertyAttributeFullName!) ||
- attributeName.StartsWith(AttributesGenerator.MvvmLightPropertyAttributeFullName!));
+ attributeName.StartsWith(AttributesGenerator.MvvmLightPropertyAttributeFullName!) ||
+ attributeName.StartsWith(AttributesGenerator.MvvmToolkitPropertyAttributeFullName!));
}
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators/Info/ContextInfo.cs b/DevExpress.Mvvm.CodeGenerators/Info/ContextInfo.cs
index 6f794b6..7cba4d7 100644
--- a/DevExpress.Mvvm.CodeGenerators/Info/ContextInfo.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Info/ContextInfo.cs
@@ -15,6 +15,7 @@ public FrameworkAttributes(Compilation compilation, SupportedMvvm mvvm) {
SupportedMvvm.None or SupportedMvvm.Dx => InitializationGenerator.DxNamespace,
SupportedMvvm.Prism => InitializationGenerator.PrismNamespace,
SupportedMvvm.MvvmLight => InitializationGenerator.MvvmLightNamespace,
+ SupportedMvvm.MvvmToolkit => InitializationGenerator.MvvmToolkitNamespace,
_ => throw new InvalidOperationException()
};
ViewModelAttributeSymbol = compilation.GetTypeByMetadataName($"{attributeNamespace}.GenerateViewModelAttribute")!;
@@ -47,20 +48,30 @@ public PrismFrameworkAttributes(Compilation compilation)
IAASymbol = compilation.GetTypeByMetadataName("Prism.IActiveAware")!;
}
}
- class MvmLightFrameWorkAttributes : FrameworkAttributes {
+ class MvvmLightFrameworkAttributes : FrameworkAttributes {
public INamedTypeSymbol ICUSymbol { get; }
- public MvmLightFrameWorkAttributes(Compilation compilation)
+ public MvvmLightFrameworkAttributes(Compilation compilation)
: base(compilation, SupportedMvvm.MvvmLight) {
ICUSymbol = compilation.GetTypeByMetadataName("GalaSoft.MvvmLight.ICleanup")!;
}
}
+ class MvvmToolkitFrameworkAttributes : FrameworkAttributes {
+ public INamedTypeSymbol ObservableRecipientSymbol { get; }
+ public INamedTypeSymbol ObservableValidatorSymbol { get; }
+ public MvvmToolkitFrameworkAttributes(Compilation compilation)
+ : base(compilation, SupportedMvvm.MvvmToolkit) {
+ ObservableRecipientSymbol = compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableRecipient")!;
+ ObservableValidatorSymbol = compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableValidator")!;
+ }
+ }
class ContextInfo {
public GeneratorExecutionContext Context { get; }
public Compilation Compilation { get; }
public DXFrameworkAttributes? Dx { get; }
public PrismFrameworkAttributes? Prism { get; }
- public MvmLightFrameWorkAttributes? MvvmLight { get; }
+ public MvvmLightFrameworkAttributes? MvvmLight { get; }
+ public MvvmToolkitFrameworkAttributes? MvvmToolkit { get; }
public INamedTypeSymbol INPCedSymbol { get; }
public INamedTypeSymbol INPCingSymbol { get; }
@@ -83,7 +94,9 @@ public ContextInfo(GeneratorExecutionContext context, Compilation compilation) {
if(AvailableMvvm.Contains(SupportedMvvm.Prism))
Prism = new PrismFrameworkAttributes(Compilation);
if(AvailableMvvm.Contains(SupportedMvvm.MvvmLight))
- MvvmLight = new MvmLightFrameWorkAttributes(Compilation);
+ MvvmLight = new MvvmLightFrameworkAttributes(Compilation);
+ if(AvailableMvvm.Contains(SupportedMvvm.MvvmToolkit))
+ MvvmToolkit = new MvvmToolkitFrameworkAttributes(Compilation);
INPCedSymbol = compilation.GetTypeByMetadataName(typeof(INotifyPropertyChanged).FullName)!;
INPCingSymbol = compilation.GetTypeByMetadataName(typeof(INotifyPropertyChanging).FullName)!;
@@ -97,31 +110,35 @@ public ContextInfo(GeneratorExecutionContext context, Compilation compilation) {
SupportedMvvm.None or SupportedMvvm.Dx => Dx!,
SupportedMvvm.Prism => Prism!,
SupportedMvvm.MvvmLight => MvvmLight!,
+ SupportedMvvm.MvvmToolkit => MvvmToolkit!,
_ => throw new InvalidOperationException()
};
public static bool GetIsWinUI(Compilation compilation) => GetIsDxMvvmAvailable(compilation) && compilation.GetTypeByMetadataName("DevExpress.Mvvm.POCO.ViewModelSource") == null;
- static bool GetIsDxMvvmAvailable(Compilation compilation) => compilation.GetTypeByMetadataName("DevExpress.Mvvm.DelegateCommand") != null;
- static bool GetIsPrismAvailable(Compilation compilation) => compilation.GetTypeByMetadataName("Prism.Commands.DelegateCommand") != null;
- static bool GetIsMvvmLightAvailable(Compilation compilation) => compilation.GetTypeByMetadataName("GalaSoft.MvvmLight.Command.RelayCommand") != null;
- public static bool GetIsMvvmLightCommandWpfAvalible(Compilation compilation) => compilation.GetTypeByMetadataName("GalaSoft.MvvmLight.CommandWpf.RelayCommand") != null;
+ static bool GetIsDxMvvmAvailable(Compilation compilation) => IsTypeAvailable(compilation, "DevExpress.Mvvm.DelegateCommand");
+ public static bool GetIsMvvmLightCommandAvalible(Compilation compilation) => IsTypeAvailable(compilation, "GalaSoft.MvvmLight.Command.RelayCommand");
+ public static bool GetIsMvvmLightCommandWpfAvalible(Compilation compilation) => IsTypeAvailable(compilation, "GalaSoft.MvvmLight.CommandWpf.RelayCommand");
+ static bool IsTypeAvailable(Compilation compilation, string type) => compilation.GetTypeByMetadataName(type) != null;
public static List GetAvailableMvvm(Compilation compilation) {
List available = new();
if(GetIsDxMvvmAvailable(compilation))
available.Add(SupportedMvvm.Dx);
- if(GetIsPrismAvailable(compilation))
+ if(IsTypeAvailable(compilation, "Prism.Commands.DelegateCommand"))
available.Add(SupportedMvvm.Prism);
- if(GetIsMvvmLightAvailable(compilation))
+ if(GetIsMvvmLightCommandAvalible(compilation))
available.Add(SupportedMvvm.MvvmLight);
+ if(IsTypeAvailable(compilation, "Microsoft.Toolkit.Mvvm.Input.RelayCommand"))
+ available.Add(SupportedMvvm.MvvmToolkit);
if(!available.Any())
available.Add(SupportedMvvm.None);
return available;
}
}
internal enum SupportedMvvm {
- None = 0,
- Dx = 1,
- Prism = 2,
- MvvmLight = 3,
+ None,
+ Dx,
+ Prism,
+ MvvmLight,
+ MvvmToolkit,
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators/Info/INPCInfo.cs b/DevExpress.Mvvm.CodeGenerators/Info/INPCInfo.cs
index 474ce9d..4c4c7a0 100644
--- a/DevExpress.Mvvm.CodeGenerators/Info/INPCInfo.cs
+++ b/DevExpress.Mvvm.CodeGenerators/Info/INPCInfo.cs
@@ -8,30 +8,30 @@ class INPCInfo {
readonly bool hasImplementationInCurrentClass;
public bool HasAttribute { get; }
- public bool HasRaiseMethodWithEventArgsParameter { get; }
- public bool HasRaiseMethodWithStringParameter { get; }
+ public bool HasMethodWithEventArgsPrefix { get; }
+ public bool HasMethodWithStringPrefix { get; }
public string RaiseMethodImplementation { get; }
public static INPCInfo GetINPCedInfo(ContextInfo info, INamedTypeSymbol classSymbol, SupportedMvvm mvvm) =>
new INPCInfo(classSymbol,
info.INPCedSymbol,
symbol => AttributeHelper.HasAttribute(symbol, info.GetFrameworkAttributes(mvvm).ViewModelAttributeSymbol),
- "RaisePropertyChanged",
+ mvvm.GetRasiePrefix() + "PropertyChanged",
"System.ComponentModel.PropertyChangedEventArgs",
- "void RaisePropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);");
+ $"void {mvvm.GetRasiePrefix().ToStringValue()}PropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e);");
public static INPCInfo GetINPCingInfo(ContextInfo info, INamedTypeSymbol classSymbol, SupportedMvvm mvvm) =>
new INPCInfo(classSymbol,
info.INPCingSymbol,
symbol => AttributeHelper.HasAttribute(symbol, info.GetFrameworkAttributes(mvvm).ViewModelAttributeSymbol) &&
AttributeHelper.GetPropertyActualValue(symbol, info.GetFrameworkAttributes(mvvm).ViewModelAttributeSymbol, AttributesGenerator.ImplementINPCing, false),
- "RaisePropertyChanging",
+ mvvm.GetRasiePrefix() + "PropertyChanging",
"System.ComponentModel.PropertyChangingEventArgs",
- "void RaisePropertyChanging(PropertyChangingEventArgs e) => PropertyChanging?.Invoke(this, e);");
+ $"void {mvvm.GetRasiePrefix().ToStringValue()}PropertyChanging(PropertyChangingEventArgs e) => PropertyChanging?.Invoke(this, e);");
public bool HasNoImplementation() =>
HasAttribute && !hasImplementation;
public bool ShouldImplementRaiseMethod() =>
- HasAttribute && !HasRaiseMethodWithEventArgsParameter && (!hasImplementation || hasImplementationInCurrentClass);
+ HasAttribute && !HasMethodWithEventArgsPrefix && (!hasImplementation || hasImplementationInCurrentClass);
INPCInfo(INamedTypeSymbol classSymbol, INamedTypeSymbol interfaceSymbol, Func checkAttribute, string methodName, string eventArgsParameter, string raiseMethodImplementation) {
HasAttribute = checkAttribute(classSymbol);
@@ -39,11 +39,11 @@ public bool ShouldImplementRaiseMethod() =>
if(HasAttribute && hasImplementation)
hasImplementationInCurrentClass = true;
- HasRaiseMethodWithEventArgsParameter = HasMethod(classSymbol, methodName, eventArgsParameter, true);
- HasRaiseMethodWithStringParameter = HasMethod(classSymbol, methodName, "string", true);
+ HasMethodWithEventArgsPrefix = HasRaiseMethod(classSymbol, methodName, eventArgsParameter, true);
+ HasMethodWithStringPrefix = HasRaiseMethod(classSymbol, methodName, "string", true);
bool isRaiseMethodGenerated = false;
- for(INamedTypeSymbol parent = classSymbol.BaseType!; parent != null; parent = parent.BaseType!) {
+ foreach(INamedTypeSymbol parent in classSymbol.GetParents()) {
bool hasAttribute = checkAttribute(parent);
bool hasImplementation = ClassHelper.IsInterfaceImplementedInCurrentClass(parent, interfaceSymbol);
if(hasAttribute || hasImplementation)
@@ -53,21 +53,26 @@ public bool ShouldImplementRaiseMethod() =>
if(hasAttribute)
isRaiseMethodGenerated = true;
- if(!HasRaiseMethodWithEventArgsParameter)
- HasRaiseMethodWithEventArgsParameter = HasMethod(parent, methodName, eventArgsParameter);
- if(!HasRaiseMethodWithStringParameter)
- HasRaiseMethodWithStringParameter = HasMethod(parent, methodName, "string");
+ if(!HasMethodWithEventArgsPrefix)
+ HasMethodWithEventArgsPrefix = HasRaiseMethod(parent, methodName, eventArgsParameter, false);
+ if(!HasMethodWithStringPrefix)
+ HasMethodWithStringPrefix = HasRaiseMethod(parent, methodName, "string", false);
}
if(isRaiseMethodGenerated)
- HasRaiseMethodWithEventArgsParameter = true;
+ HasMethodWithEventArgsPrefix = true;
RaiseMethodImplementation = raiseMethodImplementation;
}
- bool HasMethod(INamedTypeSymbol classSymbol, string methodName, string parameterType, bool ignorePrivateAccessibility = false) =>
- CommandHelper.GetMethods(classSymbol,
- symbol => (symbol.DeclaredAccessibility != Accessibility.Private || ignorePrivateAccessibility) &&
- symbol.ReturnsVoid &&
- symbol.Name == methodName &&
- symbol.Parameters.Length == 1 && symbol.Parameters.First().Type.ToDisplayString(NullableFlowState.None) == parameterType)
- .Any();
+
+ bool HasRaiseMethod(INamedTypeSymbol classSymbol, string methodName, string parameterType, bool ignorePrivateAccessibility) {
+ return classSymbol
+ .GetMembers()
+ .OfType()
+ .Any(symbol => {
+ return (symbol.DeclaredAccessibility != Accessibility.Private || ignorePrivateAccessibility) &&
+ symbol.ReturnsVoid &&
+ symbol.Name == methodName &&
+ symbol.Parameters.Length == 1 && symbol.Parameters.First().Type.ToDisplayString(NullableFlowState.None) == parameterType;
+ });
+ }
}
}
diff --git a/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/AttributesGenerator.cs b/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/AttributesGenerator.cs
index b81c67e..9e30f93 100644
--- a/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/AttributesGenerator.cs
+++ b/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/AttributesGenerator.cs
@@ -5,6 +5,7 @@ public static class AttributesGenerator {
public static readonly string DxPropertyAttributeFullName = $"{InitializationGenerator.DxNamespace}.GeneratePropertyAttribute";
public static readonly string PrismPropertyAttributeFullName = $"{InitializationGenerator.PrismNamespace}.GeneratePropertyAttribute";
public static readonly string MvvmLightPropertyAttributeFullName = $"{InitializationGenerator.MvvmLightNamespace}.GeneratePropertyAttribute";
+ public static readonly string MvvmToolkitPropertyAttributeFullName = $"{InitializationGenerator.MvvmToolkitNamespace}.GeneratePropertyAttribute";
public const string ImplementIDEI = "ImplementIDataErrorInfo";
public const string ImplementINPCing = "ImplementINotifyPropertyChanging";
@@ -18,6 +19,8 @@ public static class AttributesGenerator {
public const string OnChangedMethod = "OnChangedMethod";
public const string OnChangingMethod = "OnChangingMethod";
public const string SetterAccessModifier = "SetterAccessModifier";
+ public const string Broadcast = "Broadcast";
+ public const string Validate = "Validate";
public const string AllowMultipleExecution = "AllowMultipleExecution";
public const string UseCommandManager = "UseCommandManager";
@@ -32,6 +35,7 @@ internal static string GetSourceCode(SupportedMvvm mvvm, bool isWinUI) =>
SupportedMvvm.Dx => isWinUI ? dxwinUISourceCode : dxMvvmSourceCode,
SupportedMvvm.Prism => prismMvvmSourceCode,
SupportedMvvm.MvvmLight => mvvmLightSourceCode,
+ SupportedMvvm.MvvmToolkit => mvvmToolkitSourceCode,
SupportedMvvm.None => commonSourceCode,
_ => throw new InvalidOperationException()
};
@@ -323,6 +327,68 @@ class GeneratePropertyAttribute : Attribute {
public AccessModifier SetterAccessModifier { get; set; }
}
+ ///
+ /// Indicates that the View Model Code Generator should process this method and produce a Command.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ class GenerateCommandAttribute : Attribute {
+ ///
+ /// Specifies a custom CanExecute method name. If the property is not specified, the method’s name should follow the Can[ActionName] pattern.
+ ///
+ public string? CanExecuteMethod { get; set; }
+ ///
+ /// Specifies a custom Command name. The default value is [ActionName]Command.
+ ///
+ public string? Name { get; set; }
+ }";
+ const string mvvmToolkitSourceCode = @" ///
+ /// Indicates that the View Model Code Generator should process this class and produce a View Model.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ class GenerateViewModelAttribute : Attribute {
+ ///
+ /// Implements
+ /// INotifyPropertyChanging.
+ ///
+ public bool ImplementINotifyPropertyChanging { get; set; }
+ }
+
+ ///
+ /// Indicates that the View Model Code Generator should process this field and produce a property.
+ ///
+ [AttributeUsage(AttributeTargets.Field)]
+ class GeneratePropertyAttribute : Attribute {
+ ///
+ /// Assigns a virtual modifier to the property.
+ ///
+ public bool IsVirtual { get; set; }
+ ///
+ /// Specifies the name of the method invoked after the property value is changed.
+ /// If the property is not specified, the method’s name should follow the On[PropertyName]Changed pattern.
+ ///
+ public string? OnChangedMethod { get; set; }
+ ///
+ /// Specifies the name of the method invoked when the property value is changing.
+ /// If the property is not specified, the method’s name should follow the On[PropertyName]Changing pattern.
+ ///
+ public string? OnChangingMethod { get; set; }
+ ///
+ /// Specifies an access modifier for a set accessor. The default value is the same as a property’s modifier.
+ /// Available values: Public, Private, Protected, Internal, ProtectedInternal, PrivateProtected.
+ ///
+ public AccessModifier SetterAccessModifier { get; set; }
+ ///
+ /// Broadcasts a PropertyChangedMessage after the property value is changed.
+ /// Inherit your class from the ObservableRecipient class to enable this functionality.
+ ///
+ public bool Broadcast{ get; set; }
+ ///
+ /// Validates property value and raises the ErrorsChanged event if needed.
+ /// Inherit your class from the ObservableValidator class to enable this functionality.
+ ///
+ public bool Validate{ get; set; }
+ }
+
///
/// Indicates that the View Model Code Generator should process this method and produce a Command.
///
diff --git a/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/InitializationGenerator.cs b/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/InitializationGenerator.cs
index 5f6e9af..498b517 100644
--- a/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/InitializationGenerator.cs
+++ b/DevExpress.Mvvm.CodeGenerators/InitializationGenerator/InitializationGenerator.cs
@@ -5,6 +5,7 @@ static class InitializationGenerator {
public const string DxNamespace = "DevExpress.Mvvm.CodeGenerators";
public const string PrismNamespace = "DevExpress.Mvvm.CodeGenerators.Prism";
public const string MvvmLightNamespace = "DevExpress.Mvvm.CodeGenerators.MvvmLight";
+ public const string MvvmToolkitNamespace = "DevExpress.Mvvm.CodeGenerators.MvvmToolkit";
public static string GetSourceCode(SupportedMvvm mvvm, bool isWinUI) =>
$@"using System;
@@ -16,6 +17,7 @@ public static string GetSourceCode(SupportedMvvm mvvm, bool isWinUI) =>
SupportedMvvm.None or SupportedMvvm.Dx => DxNamespace,
SupportedMvvm.Prism => PrismNamespace,
SupportedMvvm.MvvmLight => MvvmLightNamespace,
+ SupportedMvvm.MvvmToolkit => MvvmToolkitNamespace,
_ => throw new InvalidOperationException()
}} {{
{AccessModifierGenerator.GetSourceCode()}
diff --git a/Readme.md b/Readme.md
index a164470..bda1deb 100644
--- a/Readme.md
+++ b/Readme.md
@@ -82,6 +82,15 @@ Your project should meet the following requirements:
- .NET Framework v4.6.1+ or .NET Core v3.0+
- Visual Studio v16.9.0+
+## Supported MVVM Frameworks
+
+Our View Model Code Generator [supports](https://docs.devexpress.com/WPF/402989/mvvm-framework/viewmodels/compile-time-generated-viewmodels#third-party-libraries-support) following MVVM frameworks:
+- [DevExpress WPF MVVM Framework](https://docs.devexpress.com/WPF/15112/mvvm-framework)
+- [DevExpress WinUI MVVM Framework](https://docs.devexpress.com/WinUI/102569/mvvm-framework)
+- [Microsoft MVVM Toolkit](https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction)
+- [MVVM Light Toolkit](https://github.com/lbugnion/mvvmlight)
+- [Prism Library](https://prismlibrary.com)
+
## Prepare Your Project
Prepare your project as outlined below to enable support for View Models generated at compile time:
@@ -114,16 +123,19 @@ Prepare your project as outlined below to enable support for View Models generat
## Release Notes
+### 22.1.1
+- Our View Model Code Generator now [supports](https://docs.devexpress.com/WPF/402989/mvvm-framework/viewmodels/compile-time-generated-viewmodels#microsoft-mvvm-toolkit) the [Microsoft MVVM Toolkit](https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction).
+
### 22.1.0
- The View Model Code Generator now supports the updated WinUI MVVM Framework that is available in the **DevExpress.WinUI.Mvvm.v22.1** assembly. If your **WinUI** project uses **DevExpress.Mvvm.v21.2**, replace it with **DevExpress.WinUI.Mvvm.v22.1**.
### 21.2.2
-- Our View Model Code Generator now supports the [MVVM Light Toolkit](https://github.com/lbugnion/mvvmlight).
+- Our View Model Code Generator now [supports](https://docs.devexpress.com/WPF/402989/mvvm-framework/viewmodels/compile-time-generated-viewmodels#mvvm-light-toolkit) the [MVVM Light Toolkit](https://github.com/lbugnion/mvvmlight).
- We implemented the following suggestion: [Proposal: additional attributes for generated commands](https://github.com/DevExpress/DevExpress.Mvvm.CodeGenerators/issues/14).
### 21.2.1
-Our View Model Code Generator now supports the [Prism Library](https://prismlibrary.com).
+Our View Model Code Generator now [supports](https://docs.devexpress.com/WPF/402989/mvvm-framework/viewmodels/compile-time-generated-viewmodels#prism-library) the [Prism Library](https://prismlibrary.com).
### 21.1.3