Browse Source

1. 优化WPF MVVM命令
2. OPCUA修改点击节点触发展示

Shun 2 years ago
parent
commit
a775e45313

+ 4 - 3
src/YSAI.Core.Wpf/MWindowController.cs

@@ -1,4 +1,5 @@
-using System.Drawing;
+using CommunityToolkit.Mvvm.Input;
+using System.Drawing;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
@@ -216,7 +217,7 @@ namespace YSAI.Core.Wpf
         /// <summary>
         /// 确认或是按钮点击
         /// </summary>
-        public ICommand OkOrYes { get => new CommandX(OnOkOrYes); }
+        public ICommand OkOrYes { get => new RelayCommand(OnOkOrYes); }
 
         public void OnOkOrYes()
         {
@@ -227,7 +228,7 @@ namespace YSAI.Core.Wpf
         /// <summary>
         /// 取消或否按钮点击
         /// </summary>
-        public ICommand CancelOrNo { get => new CommandX(OnCancelOrNo); }
+        public ICommand CancelOrNo { get => new RelayCommand(OnCancelOrNo); }
 
         public void OnCancelOrNo()
         {

+ 1 - 0
src/YSAI.Core.Wpf/YSAI.Core.Wpf.csproj

@@ -20,6 +20,7 @@
 	  <None Remove="themes\Image\ContentBackgroundPicture.png" />
 	</ItemGroup>
 	<ItemGroup>
+		<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
 		<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
 	</ItemGroup>
 	<ItemGroup>

+ 24 - 25
src/YSAI.Core.Wpf/controls/ledgauge/ColorModel.cs

@@ -1,4 +1,3 @@
-using System;
 using System.Diagnostics;
 using System.Drawing;
 using YSAI.Core.Wpf.mvvm;
@@ -60,10 +59,10 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 red = (int)color.R;
                 green = (int)color.G;
                 blue = (int)color.B;
-                RaisePropertyChanged("R");
-                RaisePropertyChanged("G");
-                RaisePropertyChanged("B");
-                RaisePropertyChanged("Color");
+                OnPropertyChanged("R");
+                OnPropertyChanged("G");
+                OnPropertyChanged("B");
+                OnPropertyChanged("Color");
             }
         }
 
@@ -81,7 +80,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 color = Color.FromArgb((byte)A, (byte)R, (byte)G, (byte)B);
                 RgbToHsl();
                 RgbToYuv();
-                RaisePropertyChanged("A");
+                OnPropertyChanged("A");
             }
         }
 
@@ -99,7 +98,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 color = Color.FromArgb((byte)A, (byte)R, (byte)G, (byte)B);
                 RgbToHsl();
                 RgbToYuv();
-                RaisePropertyChanged("R");
+                OnPropertyChanged("R");
             }
         }
 
@@ -117,7 +116,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 color = Color.FromArgb((byte)A, (byte)R, (byte)G, (byte)B);
                 RgbToHsl();
                 RgbToYuv();
-                RaisePropertyChanged("G");
+                OnPropertyChanged("G");
             }
         }
 
@@ -135,7 +134,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 color = Color.FromArgb((byte)A, (byte)R, (byte)G, (byte)B);
                 RgbToHsl();
                 RgbToYuv();
-                RaisePropertyChanged("B");
+                OnPropertyChanged("B");
             }
         }
 
@@ -152,7 +151,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 hue = LimitHue(value);
                 HslToRgb();
                 RgbToYuv();
-                RaisePropertyChanged("Hue");
+                OnPropertyChanged("Hue");
             }
         }
 
@@ -169,7 +168,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 saturation = slRange.Cap(value);
                 HslToRgb();
                 RgbToYuv();
-                RaisePropertyChanged("Saturation");
+                OnPropertyChanged("Saturation");
             }
         }
 
@@ -186,7 +185,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 lightness = slRange.Cap(value);
                 HslToRgb();
                 RgbToYuv();
-                RaisePropertyChanged("Lightness");
+                OnPropertyChanged("Lightness");
             }
         }
 
@@ -203,7 +202,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 y = yuvRange.Cap(value);
                 YuvToRgb();
                 RgbToHsl();
-                RaisePropertyChanged("Y");
+                OnPropertyChanged("Y");
             }
         }
 
@@ -220,7 +219,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 u = yuvRange.Cap(value);
                 YuvToRgb();
                 RgbToHsl();
-                RaisePropertyChanged("U");
+                OnPropertyChanged("U");
             }
         }
 
@@ -237,7 +236,7 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 v = yuvRange.Cap(value);
                 YuvToRgb();
                 RgbToHsl();
-                RaisePropertyChanged("V");
+                OnPropertyChanged("V");
             }
         }
 
@@ -351,9 +350,9 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                     hue = LimitHue(60.0 * (4.0 + num6 - num5));
                 }
             }
-            RaisePropertyChanged("Lightness");
-            RaisePropertyChanged("Hue");
-            RaisePropertyChanged("Saturation");
+            OnPropertyChanged("Lightness");
+            OnPropertyChanged("Hue");
+            OnPropertyChanged("Saturation");
             convertingRgbToHsl = false;
         }
 
@@ -377,10 +376,10 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                     blue = Convert(rm, num, hue - 120.0);
                 }
                 color = Color.FromArgb((byte)A, (byte)Math.Round(red), (byte)Math.Round(green), (byte)Math.Round(blue));
-                RaisePropertyChanged("R");
-                RaisePropertyChanged("G");
-                RaisePropertyChanged("B");
-                RaisePropertyChanged("Color");
+                OnPropertyChanged("R");
+                OnPropertyChanged("G");
+                OnPropertyChanged("B");
+                OnPropertyChanged("Color");
                 convertingHslToRgb = false;
             }
         }
@@ -418,9 +417,9 @@ namespace YSAI.Core.Wpf.controls.ledgauge
                 y = yuvRange.Cap(0.299 * red + 0.587 * green + 0.114 * blue);
                 u = yuvRange.Cap(blue - y);
                 v = yuvRange.Cap(red - y);
-                RaisePropertyChanged("Y");
-                RaisePropertyChanged("U");
-                RaisePropertyChanged("V");
+                OnPropertyChanged("Y");
+                OnPropertyChanged("U");
+                OnPropertyChanged("V");
                 convertingRgbToYuv = false;
             }
         }

+ 6 - 7
src/YSAI.Core.Wpf/controls/pagebar/PageBarControl.xaml.cs

@@ -1,8 +1,7 @@
-using System;
+using CommunityToolkit.Mvvm.Input;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
-using YSAI.Core.Wpf.mvvm;
 
 namespace YSAI.Core.Wpf.controls.pagebar
 {
@@ -232,7 +231,7 @@ namespace YSAI.Core.Wpf.controls.pagebar
                 Content = "上一页",
                 Value = PageIndex - 1,
                 IsEnabled = PageIndex != 1 && pageCount != 1,
-                PageNumberCommand = new Command(PageNumberChanged)
+                PageNumberCommand = new RelayCommand<object>(PageNumberChanged)
             };
             this.Items.Add(previousPage);
 
@@ -241,7 +240,7 @@ namespace YSAI.Core.Wpf.controls.pagebar
                 Content = "1",
                 Value = 1,
                 IsEnabled = true,
-                PageNumberCommand = new Command(PageNumberChanged)
+                PageNumberCommand = new RelayCommand<object>(PageNumberChanged)
             });
 
             int begin;
@@ -271,7 +270,7 @@ namespace YSAI.Core.Wpf.controls.pagebar
                     Value = i,
                     Content = i.ToString(),
                     IsEnabled = true,
-                    PageNumberCommand = new Command(PageNumberChanged)
+                    PageNumberCommand = new RelayCommand<object>(PageNumberChanged)
                 };
 
                 if (pageCount > 9)
@@ -299,7 +298,7 @@ namespace YSAI.Core.Wpf.controls.pagebar
                     Content = pageCount.ToString(),
                     Value = pageCount,
                     IsEnabled = true,
-                    PageNumberCommand = new Command(PageNumberChanged)
+                    PageNumberCommand = new RelayCommand<object>(PageNumberChanged)
                 });
             }
 
@@ -309,7 +308,7 @@ namespace YSAI.Core.Wpf.controls.pagebar
                 Content = "下一页",
                 Value = PageIndex + 1,
                 IsEnabled = PageIndex != pageCount && pageCount != 1,
-                PageNumberCommand = new Command(PageNumberChanged)
+                PageNumberCommand = new RelayCommand<object>(PageNumberChanged)
             };
             this.Items.Add(nextPage);
         }

+ 0 - 315
src/YSAI.Core.Wpf/mvvm/Command.cs

@@ -1,315 +0,0 @@
-using System;
-using System.Windows.Input;
-
-namespace YSAI.Core.Wpf.mvvm
-{
-    /// <summary>
-    /// 带参命令
-    /// </summary>
-    public class Command : ICommand
-    {
-        /// <summary>
-        /// 判断命令是否可以执行的方法
-        /// </summary>
-        private Func<object, bool> _canExecute;
-
-        /// <summary>
-        /// 命令需要执行的方法
-        /// </summary>
-        private Action<object> _execute;
-
-        /// <summary>
-        /// 创建一个命令
-        /// </summary>
-        /// <param name="execute">命令要执行的方法</param>
-        public Command(Action<object> execute) : this(execute, null)
-        {
-        }
-
-        /// <summary>
-        /// 创建一个命令
-        /// </summary>
-        /// <param name="execute">命令要执行的方法</param>
-        /// <param name="canExecute">判断命令是否能够执行的方法</param>
-        public Command(Action<object> execute, Func<object, bool> canExecute)
-        {
-            _execute = execute;
-            _canExecute = canExecute;
-        }
-
-        /// <summary>
-        /// 判断命令是否可以执行
-        /// </summary>
-        /// <param name="parameter">命令传入的参数</param>
-        /// <returns>是否可以执行</returns>
-        public bool CanExecute(object parameter)
-        {
-            if (_canExecute == null) return true;
-            return _canExecute(parameter);
-        }
-
-        /// <summary>
-        /// 执行命令
-        /// </summary>
-        /// <param name="parameter"></param>
-        public void Execute(object parameter)
-        {
-            if (_execute != null && CanExecute(parameter))
-            {
-                _execute(parameter);
-            }
-        }
-
-        /// <summary>
-        /// 事件追加、移除
-        /// </summary>
-        public event EventHandler CanExecuteChanged
-        {
-            add
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested += value;
-                }
-            }
-            remove
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested -= value;
-                }
-            }
-        }
-    }
-
-    /// <summary>
-    /// 带参事件命令
-    /// </summary>
-    /// <typeparam name="T"></typeparam>
-    public class Command<T> : ICommand
-    {
-        /// <summary>
-        /// 判断命令是否可以执行的方法
-        /// </summary>
-        private Func<T, bool> _canExecute;
-
-        /// <summary>
-        /// 命令需要执行的方法
-        /// </summary>
-        private Action<T> _execute;
-
-        /// <summary>
-        /// 创建一个命令
-        /// </summary>
-        /// <param name="execute">命令要执行的方法</param>
-        public Command(Action<T> execute) : this(execute, null) { }
-
-        /// <summary>
-        /// 创建一个命令
-        /// </summary>
-        /// <param name="execute">命令要执行的方法</param>
-        /// <param name="canExecute">判断命令是否能够执行的方法</param>
-        public Command(Action<T> execute, Func<T, bool> canExecute)
-        {
-            _execute = execute;
-            _canExecute = canExecute;
-        }
-
-        /// <summary>
-        /// 判断命令是否可以执行
-        /// </summary>
-        /// <param name="parameter">命令传入的参数</param>
-        /// <returns>是否可以执行</returns>
-        public bool CanExecute(object parameter)
-        {
-            if (_canExecute == null) return true;
-            return _canExecute((T)parameter);
-        }
-
-        /// <summary>
-        /// 执行命令
-        /// </summary>
-        /// <param name="parameter"></param>
-        public void Execute(object parameter)
-        {
-            if (_execute != null && CanExecute(parameter))
-            {
-                _execute((T)parameter);
-            }
-        }
-
-        /// <summary>
-        /// 事件追加、移除
-        /// </summary>
-        public event EventHandler CanExecuteChanged
-        {
-            add
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested += value;
-                }
-            }
-            remove
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested -= value;
-                }
-            }
-        }
-    }
-
-    /// <summary>
-    /// 命令
-    /// </summary>
-    public class CommandX : ICommand
-    {
-        /// <summary>
-        /// 命令能否执行
-        /// </summary>
-        private readonly Func<bool> _canExecute;
-
-        /// <summary>
-        /// 命令执行的方法
-        /// </summary>
-        private readonly Action _execute;
-
-        /// <summary>
-        /// 命令的构造函数
-        /// </summary>
-        /// <param name="action">命令需执行的方法</param>
-        public CommandX(Action action) : this(action, null) { }
-
-        /// <summary>
-        /// 命令的构造函数
-        /// </summary>
-        /// <param name="action">命令需执行的方法</param>
-        /// <param name="canExecute">命令是否可以执行的方法</param>
-        public CommandX(Action action, Func<bool> canExecute)
-        {
-            _execute = action;
-            _canExecute = canExecute;
-        }
-
-        /// <summary>
-        /// 检测命令
-        /// </summary>
-        /// <param name="parameter"></param>
-        /// <returns></returns>
-        /// <exception cref="NotImplementedException"></exception>
-        public bool CanExecute(object parameter)
-        {
-            if (_canExecute == null)
-                return true;
-            return _canExecute();
-        }
-
-        /// <summary>
-        /// 执行命令
-        /// </summary>
-        /// <param name="parameter"></param>
-        /// <exception cref="NotImplementedException"></exception>
-        public void Execute(object parameter)
-        {
-            _execute();
-        }
-
-        /// <summary>
-        /// 事件追加、移除
-        /// </summary>
-        public event EventHandler CanExecuteChanged
-        {
-            add
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested += value;
-                }
-            }
-            remove
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested -= value;
-                }
-            }
-        }
-    }
-
-    /// <summary>
-    /// 事件命令
-    /// </summary>
-    /// <typeparam name="T"></typeparam>
-    public class CommandX<T> : ICommand
-    {
-        /// <summary>
-        /// 命令能否执行
-        /// </summary>
-        private readonly Func<bool> _canExecute;
-
-        /// <summary>
-        /// 命令执行的方法
-        /// </summary>
-        private readonly Action<T> _execute;
-
-        /// <summary>
-        /// 创建一个命令
-        /// </summary>
-        /// <param name="execute">命令要执行的方法</param>
-        public CommandX(Action<T> execute) : this(execute, null) { }
-
-        /// <summary>
-        /// 命令的构造函数
-        /// </summary>
-        /// <param name="action">命令需执行的方法</param>
-        /// <param name="canExecute">命令是否可以执行的方法</param>
-        public CommandX(Action<T> action, Func<bool> canExecute)
-        {
-            _execute = action;
-            _canExecute = canExecute;
-        }
-
-        /// <summary>
-        /// 判断命令是否可以执行
-        /// </summary>
-        /// <param name="parameter"></param>
-        /// <returns></returns>
-        public bool CanExecute(Object parameter)
-        {
-            if (_canExecute == null)
-                return true;
-            return _canExecute();
-        }
-
-        /// <summary>
-        /// 执行命令
-        /// </summary>
-        /// <param name="parameter"></param>
-        public void Execute(Object parameter)
-        {
-            _execute((T)parameter);
-        }
-
-        /// <summary>
-        /// 事件追加、移除
-        /// </summary>
-        public event EventHandler CanExecuteChanged
-        {
-            add
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested += value;
-                }
-            }
-            remove
-            {
-                if (_canExecute != null)
-                {
-                    CommandManager.RequerySuggested -= value;
-                }
-            }
-        }
-    }
-}

+ 55 - 152
src/YSAI.Core.Wpf/mvvm/NotifyObject.cs

@@ -1,162 +1,13 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
+using CommunityToolkit.Mvvm.ComponentModel;
 using System.Linq.Expressions;
-using System.Runtime.CompilerServices;
 
 namespace YSAI.Core.Wpf.mvvm
 {
     /// <summary>
     /// 通知对象
     /// </summary>
-    public class NotifyObject : INotifyPropertyChanged
+    public class NotifyObject : ObservableObject
     {
-        public static string GetPropertyName<T>(Expression<Func<T>> expression)
-        {
-            return GetPropertyNameFast(expression);
-        }
-        internal static string GetPropertyNameFast(LambdaExpression expression)
-        {
-            MemberExpression memberExpression = expression.Body as MemberExpression;
-            if (memberExpression == null)
-            {
-                throw new ArgumentException("MemberExpression is expected in expression.Body", "NotifyObject");
-            }
-            const string vblocalPrefix = "$VB$Local_";
-            var member = memberExpression.Member;
-            if (
-                member.MemberType == System.Reflection.MemberTypes.Field &&
-                member.Name != null &&
-                member.Name.StartsWith(vblocalPrefix))
-                return member.Name.Substring(vblocalPrefix.Length);
-            return member.Name;
-        }
-
-        public event PropertyChangedEventHandler PropertyChanged;
-        protected bool SetProperty<T>(ref T storage, T value, Expression<Func<T>> expression, Action changedCallback)
-        {
-            return SetProperty(ref storage, value, GetPropertyName(expression), changedCallback);
-        }
-        protected bool SetProperty<T>(ref T storage, T value, Expression<Func<T>> expression)
-        {
-            return SetProperty<T>(ref storage, value, expression, null);
-        }
-        protected void RaisePropertyChanged<T>(Expression<Func<T>> expression)
-        {
-            RaisePropertyChanged(GetPropertyName(expression));
-        }
-        protected void RaisePropertiesChanged<T1, T2>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2)
-        {
-            RaisePropertyChanged(expression1);
-            RaisePropertyChanged(expression2);
-        }
-        protected void RaisePropertiesChanged<T1, T2, T3>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3)
-        {
-            RaisePropertyChanged(expression1);
-            RaisePropertyChanged(expression2);
-            RaisePropertyChanged(expression3);
-        }
-        protected void RaisePropertiesChanged<T1, T2, T3, T4>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3, Expression<Func<T4>> expression4)
-        {
-            RaisePropertyChanged(expression1);
-            RaisePropertyChanged(expression2);
-            RaisePropertyChanged(expression3);
-            RaisePropertyChanged(expression4);
-        }
-        protected void RaisePropertiesChanged<T1, T2, T3, T4, T5>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3, Expression<Func<T4>> expression4, Expression<Func<T5>> expression5)
-        {
-            RaisePropertyChanged(expression1);
-            RaisePropertyChanged(expression2);
-            RaisePropertyChanged(expression3);
-            RaisePropertyChanged(expression4);
-            RaisePropertyChanged(expression5);
-        }
-        protected T GetProperty<T>(Expression<Func<T>> expression)
-        {
-            return GetPropertyCore<T>(GetPropertyName(expression));
-        }
-        protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action<T> changedCallback)
-        {
-            string propertyName = GetPropertyName(expression);
-            return SetPropertyCore(propertyName, value, changedCallback);
-        }
-        protected bool SetProperty<T>(Expression<Func<T>> expression, T value)
-        {
-            return SetProperty(expression, value, (Action)null);
-        }
-        protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action changedCallback)
-        {
-            string propertyName = GetPropertyName(expression);
-            return SetPropertyCore(propertyName, value, changedCallback);
-        }
-        protected virtual bool SetProperty<T>(ref T storage, T value, string propertyName, Action changedCallback)
-        {
-            VerifyAccess();
-            if (CompareValues<T>(storage, value))
-                return false;
-            storage = value;
-            RaisePropertyChanged(propertyName);
-            changedCallback?.Invoke();
-            return true;
-        }
-        protected bool SetProperty<T>(ref T storage, T value, string propertyName)
-        {
-            return this.SetProperty<T>(ref storage, value, propertyName, null);
-        }
-        protected T GetValue<T>([CallerMemberName] string propertyName = null)
-        {
-            GuardPropertyName(propertyName);
-            return GetPropertyCore<T>(propertyName);
-        }
-        protected bool SetValue<T>(T value, [CallerMemberName] string propertyName = null)
-        {
-            return SetValue(value, default(Action), propertyName);
-        }
-        protected bool SetValue<T>(T value, Action changedCallback, [CallerMemberName] string propertyName = null)
-        {
-            return SetPropertyCore(propertyName, value, changedCallback);
-        }
-        protected bool SetValue<T>(T value, Action<T> changedCallback, [CallerMemberName] string propertyName = null)
-        {
-            return SetPropertyCore(propertyName, value, changedCallback);
-        }
-        protected bool SetValue<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
-        {
-            return SetValue(ref storage, value, default(Action), propertyName);
-        }
-        protected bool SetValue<T>(ref T storage, T value, Action changedCallback, [CallerMemberName] string propertyName = null)
-        {
-            GuardPropertyName(propertyName);
-            return SetProperty(ref storage, value, propertyName, changedCallback);
-        }
-        static void GuardPropertyName(string propertyName)
-        {
-            if (string.IsNullOrEmpty(propertyName))
-                throw new ArgumentNullException(nameof(propertyName));
-        }
-
-        #region RaisePropertyChanged
-        protected void RaisePropertyChanged(string propertyName)
-        {
-            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-        }
-        protected void RaisePropertyChanged()
-        {
-            RaisePropertiesChanged(null);
-        }
-        protected void RaisePropertiesChanged(params string[] propertyNames)
-        {
-            if (propertyNames == null || propertyNames.Length == 0)
-            {
-                RaisePropertyChanged(string.Empty);
-                return;
-            }
-            foreach (string propertyName in propertyNames)
-            {
-                RaisePropertyChanged(propertyName);
-            }
-        }
-        #endregion
 
         #region property bag
         Dictionary<string, object> _propertyBag;
@@ -205,7 +56,7 @@ namespace YSAI.Core.Wpf.mvvm
             {
                 PropertyBag[propertyName] = value;
             }
-            RaisePropertyChanged(propertyName);
+            OnPropertyChanged(propertyName);
             return true;
         }
 
@@ -218,5 +69,57 @@ namespace YSAI.Core.Wpf.mvvm
             return EqualityComparer<T>.Default.Equals(storage, value);
         }
         #endregion
+
+
+
+
+
+
+
+
+
+
+        public static string GetPropertyName<T>(Expression<Func<T>> expression)
+        {
+            return GetPropertyNameFast(expression);
+        }
+        internal static string GetPropertyNameFast(LambdaExpression expression)
+        {
+            MemberExpression memberExpression = expression.Body as MemberExpression;
+            if (memberExpression == null)
+            {
+                throw new ArgumentException("MemberExpression is expected in expression.Body", "NotifyObject");
+            }
+            const string vblocalPrefix = "$VB$Local_";
+            var member = memberExpression.Member;
+            if (
+                member.MemberType == System.Reflection.MemberTypes.Field &&
+                member.Name != null &&
+                member.Name.StartsWith(vblocalPrefix))
+                return member.Name.Substring(vblocalPrefix.Length);
+            return member.Name;
+        }
+
+
+
+
+        protected T GetProperty<T>(Expression<Func<T>> expression)
+        {
+            return GetPropertyCore<T>(GetPropertyName(expression));
+        }
+        protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action<T> changedCallback)
+        {
+            string propertyName = GetPropertyName(expression);
+            return SetPropertyCore(propertyName, value, changedCallback);
+        }
+        protected bool SetProperty<T>(Expression<Func<T>> expression, T value)
+        {
+            return SetProperty(expression, value, (Action)null);
+        }
+        protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action changedCallback)
+        {
+            string propertyName = GetPropertyName(expression);
+            return SetPropertyCore(propertyName, value, changedCallback);
+        }
     }
 }

+ 28 - 0
src/YSAI.Core.Wpf/mvvm/RoutedEventTrigger.cs

@@ -0,0 +1,28 @@
+using Microsoft.Xaml.Behaviors;
+using System.Windows;
+namespace YSAI.Core.Wpf.mvvm
+{
+    public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
+    {
+        public RoutedEvent RoutedEvent { get; set; }
+
+        protected override void OnAttached()
+        {
+            var behavior = AssociatedObject as Behavior;
+            var associatedElement = AssociatedObject as FrameworkElement;
+            if (behavior != null) associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
+            if (associatedElement == null) throw new ArgumentException();
+            if (RoutedEvent != null) associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
+        }
+
+        private void OnRoutedEvent(object sender, RoutedEventArgs args)
+        {
+            OnEvent(args);
+        }
+
+        protected override string GetEventName()
+        {
+            return RoutedEvent.Name;
+        }
+    }
+}

+ 6 - 5
src/YSAI.Tool.Wpf/TestController.cs

@@ -1,4 +1,5 @@
-using System.IO;
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
 using System.Windows;
 using System.Windows.Input;
 using YSAI.Core.communication.net.ws.client;
@@ -52,7 +53,7 @@ namespace YSAI.Tool.Wpf
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -78,7 +79,7 @@ namespace YSAI.Tool.Wpf
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -105,7 +106,7 @@ namespace YSAI.Tool.Wpf
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -173,7 +174,7 @@ namespace YSAI.Tool.Wpf
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息

+ 9 - 8
src/YSAI.Tool.Wpf/controllers/SerialController.cs

@@ -1,4 +1,5 @@
-using System.IO;
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
 using System.Text;
 using System.Windows;
 using System.Windows.Input;
@@ -57,7 +58,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -83,7 +84,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -110,7 +111,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -178,7 +179,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -208,7 +209,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = SerialOperate.Instance(BasicsData);
@@ -223,7 +224,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -234,7 +235,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;

+ 4 - 3
src/YSAI.Tool.Wpf/controllers/SvgController.cs

@@ -1,4 +1,5 @@
-using System.Windows.Input;
+using CommunityToolkit.Mvvm.Input;
+using System.Windows.Input;
 using YSAI.Core.Wpf;
 using YSAI.Core.Wpf.mvvm;
 using YSAI.Langs;
@@ -81,7 +82,7 @@ namespace YSAI.Tool.Wpf.controllers
             }
         }
 
-        public ICommand Transition { get => new CommandX(OnTransition); }
+        public ICommand Transition { get => new RelayCommand(OnTransition); }
 
         /// <summary>
         /// 复制
@@ -92,6 +93,6 @@ namespace YSAI.Tool.Wpf.controllers
             System.Windows.Clipboard.SetDataObject(OutData);
         }
 
-        public ICommand Copy { get => new CommandX(OnCopy); }
+        public ICommand Copy { get => new RelayCommand(OnCopy); }
     }
 }

+ 9 - 8
src/YSAI.Tool.Wpf/controllers/TcpClientController.cs

@@ -1,4 +1,5 @@
-using System.IO;
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
 using System.Text;
 using System.Windows;
 using System.Windows.Input;
@@ -56,7 +57,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -82,7 +83,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -109,7 +110,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -177,7 +178,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -207,7 +208,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = TcpClientOperate.Instance(BasicsData);
@@ -222,7 +223,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -233,7 +234,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;

+ 10 - 9
src/YSAI.Tool.Wpf/controllers/TcpServiceController.cs

@@ -1,4 +1,5 @@
-using System.Collections.ObjectModel;
+using CommunityToolkit.Mvvm.Input;
+using System.Collections.ObjectModel;
 using System.IO;
 using System.Text;
 using System.Windows;
@@ -63,7 +64,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -89,7 +90,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -116,7 +117,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -184,7 +185,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -214,7 +215,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = TcpServiceOperate.Instance(BasicsData);
@@ -229,7 +230,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -241,7 +242,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;
@@ -377,7 +378,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 表格数据选中触发
         /// </summary>
-        public ICommand GridDataSelectionChanged { get => new CommandX<SelectionChangedEventArgs>(OnGridDataSelectionChanged); }
+        public ICommand GridDataSelectionChanged { get => new RelayCommand<SelectionChangedEventArgs>(OnGridDataSelectionChanged); }
         /// <summary>
         /// 触发事件
         /// </summary>

+ 34 - 25
src/YSAI.Tool.Wpf/controllers/UaClientController.cs

@@ -1,4 +1,5 @@
-using Newtonsoft.Json;
+using CommunityToolkit.Mvvm.Input;
+using Newtonsoft.Json;
 using Opc.Ua;
 using System.Collections.Concurrent;
 using System.Collections.ObjectModel;
@@ -22,6 +23,7 @@ namespace YSAI.Tool.Wpf.controllers
     {
         public UaClientController()
         {
+            DataType = 0;
             //当皮肤切换触发事件
             WindowHelper.OnSkinSwitchEvent += WindowHelper_OnSkinSwitchEvent;
             //初始化基础数据
@@ -67,7 +69,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -93,7 +95,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -108,19 +110,20 @@ namespace YSAI.Tool.Wpf.controllers
             }
         }
 
+        private string _info = string.Empty;
         /// <summary>
         /// 信息
         /// </summary>
         public string Info
         {
-            get => GetProperty(() => Info);
-            set => SetProperty(() => Info, value);
+            get => _info;
+            set => SetProperty(ref _info, value);
         }
 
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -188,7 +191,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -218,11 +221,19 @@ namespace YSAI.Tool.Wpf.controllers
             get => GetProperty(() => DataType);
             set => SetProperty(() => DataType, value);
         }
+        /// <summary>
+        /// 节点浏览是否点击
+        /// </summary>
+        public bool NodeBrowseIsChecked
+        {
+            get => GetProperty(() => NodeBrowseIsChecked);
+            set => SetProperty(() => NodeBrowseIsChecked, value);
+        }
 
         /// <summary>
         /// 隐藏节点浏览命令
         /// </summary>
-        public ICommand ToggleButton_Unchecked { get => new CommandX<RoutedEventArgs>(OnToggleButton_Unchecked); }
+        public ICommand ToggleButton_Unchecked { get => new RelayCommand<RoutedEventArgs>(OnToggleButton_Unchecked); }
         private void OnToggleButton_Unchecked(RoutedEventArgs e)
         {
             BasicsData_ToggleButtonIsChecked = false;
@@ -241,7 +252,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 显示节点浏览命令
         /// </summary>
-        public ICommand ToggleButton_Checked { get => new CommandX<RoutedEventArgs>(OnToggleButton_Checked); }
+        public ICommand ToggleButton_Checked { get => new RelayCommand<RoutedEventArgs>(OnToggleButton_Checked); }
         private void OnToggleButton_Checked(RoutedEventArgs e)
         {
             if (communication != null && communication.GetStatus().State)
@@ -270,7 +281,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = OpcUaClientOperate.Instance(BasicsData);
@@ -301,13 +312,11 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
-            OnToggleButton_Unchecked(null);
-
-
+            NodeBrowseIsChecked = false;
             OperateResult operateResult = communication.Off();
             Output(operateResult.ToJson().JsonFormatting());
         }
@@ -370,54 +379,54 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 读取
         /// </summary>
-        public ICommand Read { get => new CommandX(OnRead); }
+        public ICommand Read { get => new RelayCommand(OnRead); }
 
         /// <summary>
         /// 订阅
         /// </summary>
-        public ICommand Subscribe { get => new CommandX(OnSubscribe); }
+        public ICommand Subscribe { get => new RelayCommand(OnSubscribe); }
 
         /// <summary>
         /// 写入
         /// </summary>
-        public ICommand Write { get => new CommandX(OnWrite); }
+        public ICommand Write { get => new RelayCommand(OnWrite); }
 
         /// <summary>
         /// 取消订阅
         /// </summary>
-        public ICommand UnSubscribe { get => new CommandX(OnUnSubscribe); }
+        public ICommand UnSubscribe { get => new RelayCommand(OnUnSubscribe); }
 
         /// <summary>
         /// 树控件被选中
         /// </summary>
-        public ICommand TreeView_SelectedItemChanged { get => new CommandX<System.Windows.RoutedPropertyChangedEventArgs<object>>(OnTreeView_SelectedItemChanged); }
+        public ICommand TreeView_SelectedItemChanged { get => new RelayCommand<System.Windows.RoutedPropertyChangedEventArgs<object>>(OnTreeView_SelectedItemChanged); }
 
         /// <summary>
         /// 表格列被选中
         /// </summary>
-        public ICommand DataGrid_SelectedCellsChanged { get => new CommandX<object>(OnDataGrid_SelectedCellsChanged); }
+        public ICommand DataGrid_SelectedCellsChanged { get => new RelayCommand<object>(OnDataGrid_SelectedCellsChanged); }
 
         /// <summary>
         /// 鼠标右键在树控件按下
         /// </summary>
-        public ICommand TreeView_PreviewMouseRightButtonDown { get => new CommandX<MouseButtonEventArgs>(OnTreeView_PreviewMouseRightButtonDown); }
+        public ICommand TreeView_PreviewMouseRightButtonDown { get => new RelayCommand<MouseButtonEventArgs>(OnTreeView_PreviewMouseRightButtonDown); }
 
-        public ICommand TreeViewItem_Expanded { get => new CommandX<RoutedEventArgs>(OnTreeViewItem_Expanded); }
+        public ICommand TreeViewItem_Expanded { get => new RelayCommand<RoutedEventArgs>(OnTreeViewItem_Expanded); }
 
         /// <summary>
         /// 批量订阅
         /// </summary>
-        public ICommand ContextMenu_Subscribe { get => new CommandX<object>(OnContextMenu_Subscribe); }
+        public ICommand ContextMenu_Subscribe { get => new RelayCommand<object>(OnContextMenu_Subscribe); }
 
         /// <summary>
         /// 取消批量订阅
         /// </summary>
-        public ICommand ContextMenu_UnSubscribe { get => new CommandX<Object>(OnContextMenu_UnSubscribe); }
+        public ICommand ContextMenu_UnSubscribe { get => new RelayCommand<Object>(OnContextMenu_UnSubscribe); }
 
         /// <summary>
         /// 导出节点
         /// </summary>
-        public ICommand ContextMenu_ExpNode { get => new CommandX<object>(OnContextMenu_ExpNode); }
+        public ICommand ContextMenu_ExpNode { get => new RelayCommand<object>(OnContextMenu_ExpNode); }
 
         #region 命令实现
 

+ 9 - 8
src/YSAI.Tool.Wpf/controllers/UdpController.cs

@@ -1,4 +1,5 @@
-using System.IO;
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
 using System.Net;
 using System.Text;
 using System.Windows;
@@ -64,7 +65,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -90,7 +91,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -117,7 +118,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -185,7 +186,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -214,7 +215,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = UdpOperate.Instance(BasicsData);
@@ -230,7 +231,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -241,7 +242,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;

+ 9 - 8
src/YSAI.Tool.Wpf/controllers/WsClientController.cs

@@ -1,4 +1,5 @@
-using System.IO;
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
 using System.Text;
 using System.Windows;
 using System.Windows.Input;
@@ -53,7 +54,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -79,7 +80,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -106,7 +107,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -174,7 +175,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -204,7 +205,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = WsClientOperate.Instance(BasicsData);
@@ -219,7 +220,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -230,7 +231,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;

+ 10 - 9
src/YSAI.Tool.Wpf/controllers/WsServiceController.cs

@@ -1,4 +1,5 @@
-using System.Collections.ObjectModel;
+using CommunityToolkit.Mvvm.Input;
+using System.Collections.ObjectModel;
 using System.IO;
 using System.Text;
 using System.Windows;
@@ -58,7 +59,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导入基础数据命令
         /// </summary>
-        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+        public ICommand IncBasics { get => new RelayCommand(OnIncBasics); }
 
         /// <summary>
         /// 导入基础数据
@@ -84,7 +85,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 导出基础数据命令
         /// </summary>
-        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
 
         /// <summary>
         /// 导出基础数据
@@ -111,7 +112,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 信息框事件
         /// </summary>
-        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+        public ICommand Info_TextChanged { get => new RelayCommand<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
         /// 信息框事件
@@ -179,7 +180,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 清空信息命令
         /// </summary>
-        public ICommand Clear { get => new CommandX(OnClear); }
+        public ICommand Clear { get => new RelayCommand(OnClear); }
 
         /// <summary>
         /// 清空信息
@@ -209,7 +210,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 启动
         /// </summary>
-        public ICommand Start { get => new CommandX(OnStart); }
+        public ICommand Start { get => new RelayCommand(OnStart); }
         private void OnStart()
         {
             communication = WsServiceOperate.Instance(BasicsData);
@@ -224,7 +225,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 停止
         /// </summary>
-        public ICommand Stop { get => new CommandX(OnStop); }
+        public ICommand Stop { get => new RelayCommand(OnStop); }
         private void OnStop()
         {
             if (communication == null) return;
@@ -236,7 +237,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 发送
         /// </summary>
-        public ICommand Send { get => new CommandX(OnSend); }
+        public ICommand Send { get => new RelayCommand(OnSend); }
         private void OnSend()
         {
             if (communication == null) return;
@@ -372,7 +373,7 @@ namespace YSAI.Tool.Wpf.controllers
         /// <summary>
         /// 表格数据选中触发
         /// </summary>
-        public ICommand GridDataSelectionChanged { get => new CommandX<SelectionChangedEventArgs>(OnGridDataSelectionChanged); }
+        public ICommand GridDataSelectionChanged { get => new RelayCommand<SelectionChangedEventArgs>(OnGridDataSelectionChanged); }
         /// <summary>
         /// 触发事件
         /// </summary>

+ 10 - 10
src/YSAI.Tool.Wpf/views/UaClient.xaml

@@ -69,7 +69,7 @@
                     <ColumnDefinition Width="auto"/>
                 </Grid.ColumnDefinitions>
 
-                <ToggleButton Grid.Column="0"  Grid.ColumnSpan="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,-28,3,0" ToolTip="节点信息浏览[隐藏/显示]" Panel.ZIndex="3">
+                <ToggleButton Grid.Column="0"  Grid.ColumnSpan="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,-28,3,0" ToolTip="节点信息浏览[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding NodeBrowseIsChecked}">
                     <i:Interaction.Triggers>
                         <i:EventTrigger EventName="Unchecked">
                             <mvvm:EventCommand  Command="{Binding ToggleButton_Unchecked}" />
@@ -326,9 +326,9 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                                             </Grid.ColumnDefinitions>
                                             <RadioButton Grid.Column="0" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="String" VerticalAlignment="Center" HorizontalAlignment="Center" />
                                             <RadioButton Grid.Column="1" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Double"  VerticalAlignment="Center" HorizontalAlignment="Center" />
-                                            <RadioButton Grid.Column="2" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="Float" VerticalAlignment="Center" HorizontalAlignment="Center" />
-                                            <RadioButton Grid.Column="3" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Int"  VerticalAlignment="Center" HorizontalAlignment="Center" />
-                                            <RadioButton Grid.Column="4" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="Bool" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="2" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=2}" Style="{StaticResource RadioButtonStyle}" Content="Float" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="3" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=3}"  Style="{StaticResource RadioButtonStyle}" Content="Int"  VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="4" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=4}" Style="{StaticResource RadioButtonStyle}" Content="Bool" VerticalAlignment="Center" HorizontalAlignment="Center" />
                                         </Grid>
                                     </GroupBox>
 
@@ -352,7 +352,7 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                                                              Hint="写入数据"
                                                              CornerRadius="{DynamicResource WindowCornerRadius}" />
 
-                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="1" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
+                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="1" Command="{Binding Read}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
                                                               IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
                                                               BorderBrush="{DynamicResource Control.Border.Color}"
                                                               IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
@@ -360,7 +360,7 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                                                               Icon="{DynamicResource Read}"
                                                               Content="读取"/>
 
-                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="1" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
+                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="1" Command="{Binding Write}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
                                                               IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
                                                               BorderBrush="{DynamicResource Control.Border.Color}"
                                                               IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
@@ -368,7 +368,7 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                                                               Icon="{DynamicResource Write}"
                                                               Content="写入"/>
 
-                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="2" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
+                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="2" Command="{Binding Subscribe}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
                                                                 IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
                                                                 BorderBrush="{DynamicResource Control.Border.Color}"
                                                                 IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
@@ -376,7 +376,7 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                                                                 Icon="{DynamicResource Subscribe}"
                                                                 Content="订阅"/>
 
-                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="2" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
+                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="2" Command="{Binding UnSubscribe}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
                                                                 IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
                                                                 BorderBrush="{DynamicResource Control.Border.Color}"
                                                                 IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
@@ -530,9 +530,9 @@ Content="清空"/>
                                                 <mvvm:EventCommand  Command="{Binding TreeView_PreviewMouseRightButtonDown}" />
                                             </i:EventTrigger>
                                             <!--项被展开-->
-                                            <i:EventTrigger SourceName="TreeViewItem" EventName="Expanded">
+                                            <mvvm:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
                                                 <mvvm:EventCommand  Command="{Binding TreeViewItem_Expanded}" />
-                                            </i:EventTrigger>
+                                            </mvvm:RoutedEventTrigger>
                                         </i:Interaction.Triggers>
                                         <TreeView.ItemTemplate>
                                             <HierarchicalDataTemplate  DataType="{x:Type NodeStructuralBody:NodeStructuralBody}" ItemsSource="{Binding Children}">