wordpress 后臺拿shell正規(guī)網(wǎng)絡(luò)公司關(guān)鍵詞排名優(yōu)化
了解MVVM
- 什么是MVVM:一種設(shè)計模式
設(shè)計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當長的一段時間的試驗和錯誤總結(jié)出來的。
- 為什么需要MVVM?解決什么問題?
降低耦合、獨立開發(fā)、邏輯重用(Xamarin MAUI多平臺應(yīng)用)、可測試
響應(yīng)式布局
控件交互到MVVM模式的轉(zhuǎn)變
控件交互:基于控件的功能開發(fā)
MVVM模式
代碼/項目結(jié)構(gòu)
Models:
Views:
ViewModels:
需求:計算器,輸入:A B 輸出:通過按鈕 A+B 的結(jié)果
控件交互寫法:
XAML代碼:
<StackPanel><TextBox Text="" Name="tb_1"/><TextBlock Text="+" /><TextBox Text="" Name="tb_2"/><TextBlock Text="=" /><TextBox Text="" Name="tb_3"/><Button Content="計算" Click="Button_Click"/>
</StackPanel>
C#代碼:
private void Button_Click(object sender, RoutedEventArgs e)
{// 控制邏輯double.TryParse(this.tb_1.Text, out double value_1);double.TryParse(this.tb_2.Text, out double value_2);this.tb_3.Text = (value_1 + value_2) + "";
}
效果:
MVVM模式開發(fā):
XAML代碼:View代碼
在XAML或內(nèi)部cs文件中,綁定對應(yīng)的ViewModel
<Window x:Class="XH.MvvmLesson.Mvvm.MvvmWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:XH.MvvmLesson.Mvvm"mc:Ignorable="d"Title="MvvmWindow" Height="450" Width="800"><!--綁定ViewModel--><Window.DataContext><local:LogicClass /></Window.DataContext><StackPanel><TextBox Text="{Binding _model.Value1}" /><TextBlock Text="+" /><TextBox Text="{Binding _model.Value2}" /><TextBlock Text="=" /><TextBox Text="{Binding _model.Value3}" /><Button Content="計算" Command="{Binding BtnCommand}" CommandParameter="BtnParameter"/><Button Content="檢查狀態(tài)" Command="{Binding BtnCheckCommand}" /></StackPanel>
</Window>
ViewModel代碼:
創(chuàng)建實例,綁定View
創(chuàng)建Command對象,綁定事件
namespace XH.MvvmLesson.Mvvm
{public class LogicClass{public DataModel _model { get; set; } = new DataModel();public Command BtnCommand { get; set; }public Command BtnCheckCommand { get; set; }public LogicClass(){BtnCommand = new Command(DoLogic, CanDoLogic);BtnCheckCommand = new Command(DoCheck);_model.PropertyChanged += _model_PropertyChanged;}// 屬性變化事件private void _model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e){BtnCommand.RaiseCanExecuteChanged();}// 檢查按鈕private void DoCheck(object obj){BtnCommand.RaiseCanExecuteChanged();}// 控制邏輯private void DoLogic(object obj){_model.Value3 = _model.Value1 + _model.Value2;}// 是否可以啟用按鈕private bool CanDoLogic(object obj){return _model.Value1 > 0 && _model.Value2 > 0;}}
}
Model代碼:
INotifyPropertyChanged:使用頁面通知屬性,在屬性set的時候,調(diào)用
using System.ComponentModel;namespace XH.MvvmLesson.Mvvm
{// 針對功能所提供的數(shù)據(jù)模型public class DataModel : INotifyPropertyChanged{private double _value1;public double Value1{get { return _value1; }set{_value1 = value;PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Value1"));}}private double _value2;public double Value2{get { return _value2; }set{_value2 = value;PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Value2"));}}private double _value3;public double Value3{get { return _value3; }set{_value3 = value;// 在系統(tǒng)內(nèi)廣而告之 告訴頁面上哪個對象關(guān)注了這個實例里的這個屬性的,趕緊更新結(jié)果PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Value3"));}}// 做信息發(fā)布的對象 需要執(zhí)行這一下這個對象public event PropertyChangedEventHandler? PropertyChanged;}
}
事件Command代碼:ICommand
需要繼承ICommand接口
CanExecute:判斷是否需要啟用這個事件,等同于IsEnabled
在界面加載的時候調(diào)用一次,在每次執(zhí)行之前再調(diào)用一次
Execute:執(zhí)行事件方法
parameter:界面的CommandParameter屬性來傳值
using System.Windows.Input;namespace XH.MvvmLesson.Mvvm
{public class Command : ICommand{// 判斷綁定的當前命令實例的對象 是否可用// 比如按鈕是否可以執(zhí)行下面的邏輯public event EventHandler? CanExecuteChanged;// 外部調(diào)用public void RaiseCanExecuteChanged(){// 通知方法使用是否可以觸發(fā) 通知狀態(tài)檢查CanExecuteChanged?.Invoke(this, EventArgs.Empty);}// 作用,觸發(fā)一個時機 切換調(diào)用方的狀態(tài)是否可用public bool CanExecute(object? parameter){return _canExecute?.Invoke(parameter) != false;}// 參數(shù) 返回值private Func<object?, bool> _canExecute;// 綁定了當前命令實例的對象的執(zhí)行邏輯// 等同于 Button的Click 事件// parameter:界面的CommandParameter屬性來傳值public void Execute(object? parameter){// 委托 DoExeute?.Invoke(parameter);}public Action<object> DoExeute { get; set; }public Command(Action<object> action, Func<object?, bool> func = null){DoExeute = action;_canExecute = func;}}
}
MVVM綁定模式下的信息交互
數(shù)據(jù)類型:INotifyPropertyChanged接口
class Class1 : INotifyPropertyChanged
{public event PropertyChangedEventHandler? PropertyChanged;
}
行為動作:ICommand接口
class Class1 : ICommand
{// 調(diào)用這個方式的時候 又調(diào)用 CanExecute 方法public event EventHandler? CanExecuteChanged;// 外部調(diào)用public void RaiseCanExecuteChanged(){// 通知方法使用是否可以觸發(fā) 通知狀態(tài)檢查CanExecuteChanged?.Invoke(this, EventArgs.Empty);}// 作用,觸發(fā)一個時機 切換調(diào)用方的狀態(tài)是否可用public bool CanExecute(object? parameter){throw new NotImplementedException();}// 綁定了當前命令實例的對象的執(zhí)行邏輯// 等同于 Button的Click 事件// parameter:界面的CommandParameter屬性來傳值public void Execute(object? parameter){throw new NotImplementedException();}
}
擴展:修改數(shù)據(jù)格式,把每次的算法記錄成一個表格,并且添加刪除按鈕可以刪除
主要是修改表格的數(shù)據(jù)模板,并且每個數(shù)據(jù)增加個按鈕 進行移除,并且傳入當前集合,集合通知屬性
部分XAML代碼:
<Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><StackPanel><TextBox Text="{Binding _model.Value1,UpdateSourceTrigger=PropertyChanged}" /><TextBlock Text="+" /><TextBox Text="{Binding _model.Value2,UpdateSourceTrigger=PropertyChanged}" /><TextBlock Text="=" /><TextBox Text="{Binding _model.Value3}" /><Button Content="計算" Command="{Binding BtnCommand}" CommandParameter="BtnParameter"/><Button Content="檢查狀態(tài)" Command="{Binding BtnCheckCommand}" /></StackPanel><ListBox Grid.Column="1" ItemsSource="{Binding ResultList}" Name="lb"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding}" /><!--<TextBlock Text="{Binding State}" />--><!--只寫個Binding 是綁定當前數(shù)據(jù)源--><Button Content="刪除" CommandParameter="{Binding}"Command="{Binding DataContext.BtnDelCommand,RelativeSource={RelativeSource AncestorType=Window}}" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox></Grid>
只寫個Binding 是綁定當前數(shù)據(jù)源
部分C#代碼:
ObservableCollection:集合通知屬性
// ObservableCollection:集合通知屬性,代替List 可以通知界面修改數(shù)據(jù)
//public ObservableCollection<ResultModel> ResultList { get; set; } = new ObservableCollection<ResultModel>();
public ObservableCollection<string> ResultList { get; set; } = new ObservableCollection<string>();public Command BtnDelCommand { get; set; }public MainViewModel()
{BtnDelCommand = new Command(DoDel);
}// 刪除按鈕
private void DoDel(object obj)
{ResultList.Remove((string)obj);
}// 控制邏輯
private void DoLogic(object obj)
{_model.Value3 = _model.Value1 + _model.Value2;// 如果希望通知子項的變化(這個集合中的子項的增減)// 需要實現(xiàn)INotifyCollectionChanged接口,進行子項變化通知// 框架提供了通知集合對象ObservableCollection//ResultList.Add(new ResultModel//{// Msg = $"第{ResultList.Count + 1}次{_model.Value1} + {_model.Value2} = {_model.Value3}",//});ResultList.Add($"第{ResultList.Count + 1}次{_model.Value1} + {_model.Value2} = {_model.Value3}");
}
顯示效果:
MVVM綁定擴展
無法綁定的對象屬性
通過附加屬性進行擴展
案例:綁定ScottPlot,實現(xiàn)圖標動態(tài)刷新
View:
<Window x:Class="XH.MvvmPattern.Views.ScottPlotWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:XH.MvvmPattern.Views"xmlns:vm="clr-namespace:XH.MvvmPattern.ViewModels"xmlns:b="clr-namespace:XH.MvvmPattern.Base"mc:Ignorable="d"Title="ScottPlotWindow" Height="450" Width="800"><Window.DataContext><vm:ScottPlotViewModel /></Window.DataContext><Grid><WpfPlot Name="wpf_plot" b:ScottPlotExtension.Values="{Binding Datas}"/></Grid>
</Window>
Model:由于數(shù)據(jù)很少,數(shù)據(jù)寫在ViewModel 里面
ViewModel:
using ScottPlot;
using System.Collections.ObjectModel;
using System.Windows;namespace XH.MvvmPattern.ViewModels
{public class ScottPlotViewModel{public ObservableCollection<double> Datas { get; set; } public ScottPlotViewModel(){Datas = new ObservableCollection<double>(DataGen.RandomWalk(new Random(), 10));// 實時監(jiān)控 持續(xù)獲取數(shù)據(jù) Task.Run(async () =>{while (true){await Task.Delay(1000);Application.Current.Dispatcher.BeginInvoke(() =>{Datas.Add(new Random().NextDouble());Datas.RemoveAt(0);});}});}}
}
附加屬性:
using ScottPlot;
using System.Collections.ObjectModel;
using System.Windows;namespace XH.MvvmPattern.Base
{public class ScottPlotExtension{// 依賴附加屬性// 這個屬性里面可以知道綁定的屬性 以及被附加的對象public static ObservableCollection<double> GetValues(DependencyObject obj){return (ObservableCollection<double>)obj.GetValue(ValuesProperty);}public static void SetValues(DependencyObject obj, int value){obj.SetValue(ValuesProperty, value);}// Using a DependencyProperty as the backing store for Values. This enables animation, styling, binding, etc...public static readonly DependencyProperty ValuesProperty =DependencyProperty.RegisterAttached("Values",typeof(ObservableCollection<double>),typeof(ScottPlotExtension),new PropertyMetadata(null, new PropertyChangedCallback(OnValuesChanged)));// 當給Value賦值的時候 才會觸發(fā)private static void OnValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var plt = d as WpfPlot;var newPlt = plt.Plot;var new_list = (ObservableCollection<double>)e.NewValue;var signal = newPlt.AddSignal(new_list.ToArray());// 對集合實例進行子項增減的時候 進行回調(diào)new_list.CollectionChanged += (s, e) =>{// 由于數(shù)組長度不能變 所以是ViewModel中,長度變?yōu)?0的事件中,再觸發(fā),加個判斷if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove){signal.Update(new_list.ToArray());plt.Refresh();}};plt.Refresh();}}
}
注意:附加屬性中的屬性改變事件,只有在Value賦值的時候才會觸發(fā),但是List中間值改變不會觸發(fā),
所以需要再此事件中寫集合的值改變事件:CollectionChanged
無法綁定的動作事件
單擊鼠標左鍵 :LeftClick
雙擊鼠標左鍵:LeftDoubleClick
單擊鼠標中鍵 :MiddleClick
雙擊鼠標中鍵:MiddleDoubleClick
單擊鼠標右鍵:RightClick
雙擊鼠標右鍵:RightDoubleClick
不執(zhí)行任何操作:None
旋轉(zhuǎn)鼠標滾輪:WheelClick
鍵盤和鼠標常用方法:InputBindings
<Border.InputBindings><MouseBinding Command="{Binding BtnCommand}" MouseAction="LeftClick" /><KeyBinding Command="{Binding BtnCommand}" Key="Enter" />
</Border.InputBindings>
事件轉(zhuǎn)命令
Behavior
第一步:下載NuGet 包
第二步:引入命名空間
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
第三步:使用:
EventName:綁定的事件名稱
Command:綁定
<Border Height="40" Background="Orange"><b:Interaction.Triggers><b:EventTrigger EventName="MouseLeftButtonDown"><b:InvokeCommandAction Command="{Binding BtnCommand}" /></b:EventTrigger></b:Interaction.Triggers></Border>
自定義實現(xiàn)
思路:就是寫一個附加屬性,然后同過一個類,傳入事件名稱和事件Command,然后同過反射反射到對應(yīng)的控件事件上,進行調(diào)用即可。
C#代碼:
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;namespace XH.MvvmPattern.Base
{// 任意事件綁定public class EventExtension{// 解決:頁面至少需要傳遞兩個信息:事件名陳、命令,可以將這兩個信息進行類的打包 EventCommand// 通過EventCommand的實例進行相關(guān)信息的獲取(事件名稱、命令)// 然后進行反射事件的委托掛載,在執(zhí)行命令過程public static EventCommand GetEventTarget(DependencyObject obj){return (EventCommand)obj.GetValue(EventTargetProperty);}public static void SetEventTarget(DependencyObject obj, EventCommand value){obj.SetValue(EventTargetProperty, value);}// Using a DependencyProperty as the backing store for EventTarget. This enables animation, styling, binding, etc...public static readonly DependencyProperty EventTargetProperty =DependencyProperty.RegisterAttached("EventTarget", typeof(EventCommand), typeof(EventExtension), new PropertyMetadata(null,new PropertyChangedCallback(OnEventTargetChanged)));private static void OnEventTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){if (d is UIElement control){var eventCommand = e.NewValue as EventCommand;if (eventCommand == null) return;string eventName = eventCommand.EventName;// 獲取控件類型 Type controlType = control.GetType();bool isEvent = IsEvent(eventName, controlType);if (isEvent){EventInfo eventInfo = controlType.GetEvent(eventName);if (eventInfo != null){// 動態(tài)掛載事件MethodInfo methodInfo = typeof(EventExtension).GetMethod("OnEventRaised", BindingFlags.NonPublic | BindingFlags.Static);Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodInfo);eventInfo.AddEventHandler(control, handler);control.SetValue(EventTargetProperty, eventCommand);}}}}// 掛載事件 事件轉(zhuǎn)命令 private static void OnEventRaised(object sender, EventArgs e){DependencyObject control = sender as DependencyObject;if (control == null) return;EventCommand eventCommand = GetEventTarget(control);if (eventCommand == null) return;ICommand command = eventCommand.Command;// 如果Command 獲取為null,有可能是因為EventCommand對象的繼承有問題,需要繼承Animatableif (command != null && command.CanExecute(eventCommand.CommandParameter)){command.Execute(eventCommand.CommandParameter);}}// 判斷是不是事件private static bool IsEvent(string eventName, Type controlType){// 獲取控件類型的所有事件EventInfo[] events = controlType.GetEvents();// 檢查是否存在與給定名稱匹配的事件foreach (EventInfo eventInfo in events){if (eventInfo.Name.Equals(eventName, StringComparison.OrdinalIgnoreCase)){return true;}}return false;}}public class EventCommand : Animatable{public string EventName { get; set; }// 事件綁定public ICommand Command{get { return (ICommand)GetValue(CommandProperty); }set { SetValue(CommandProperty, value); }}// Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...public static readonly DependencyProperty CommandProperty =DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null));// 參數(shù)public object CommandParameter{get { return (object)GetValue(CommandParameterProperty); }set { SetValue(CommandParameterProperty, value); }}// Using a DependencyProperty as the backing store for CommandParameter. This enables animation, styling, binding, etc...public static readonly DependencyProperty CommandParameterProperty =DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommand), new PropertyMetadata(0));protected override Freezable CreateInstanceCore(){return (Freezable)Activator.CreateInstance(GetType());}}
}
注意:如果在掛載的時候,發(fā)現(xiàn)Command是null,或者綁定的時候目標源在FrameworkElement 或 FrameworkContentElement上的時候,需要繼承Animatable類,也不是繼承接口:ICommand
主要是仿照微軟提供的behaviors進行編寫,這個方法也是繼承Animatable才能實現(xiàn)Command 傳遞
ContextMenu綁定事件處理
XAML代碼:原因:ContextMenu在窗體之上,不在窗體之內(nèi),所以找不到窗體的數(shù)據(jù)源,需要明確指定數(shù)據(jù)源
<Window.Resources><vm:MainViewModel x:Key="mvm" />
</Window.Resources>
<Window.DataContext><!--<vm:MainViewModel />--><StaticResource ResourceKey="mvm" />
</Window.DataContext>
………………
<StackPanel.ContextMenu><ContextMenu><!--第一種方式 Source={x:Reference Name=lb}--><!--<MenuItem Header="刪除" CommandParameter="{Binding}" Command="{Binding DataContext.BtnDelCommand,Source={x:Reference Name=lb}}"/>--><!--第二種方式 把數(shù)據(jù)源當做資源調(diào)用 Source 即可--><!--原因:ContextMenu在窗體之上,不在窗體之內(nèi),所以找不到窗體的數(shù)據(jù)源,需要明確指定數(shù)據(jù)源注意:命令的數(shù)據(jù)源的指定--><MenuItem Header="刪除" CommandParameter="{Binding}" Command="{Binding BtnDelCommand,Source={StaticResource mvm}}"/></ContextMenu>
</StackPanel.ContextMenu>
自定義控件的事件綁定:
C#代碼:直接在代碼中寫依賴綁定屬性即可,在有需要的地方調(diào)用Execute
public partial class DateTimePicker :UserControl, INotifyPropertyChanged{// 命令屬性public ICommand SelectedCommand{get { return (ICommand)GetValue(SelectedCommandProperty); }set { SetValue(SelectedCommandProperty, value); }}// Using a DependencyProperty as the backing store for SelectedCommand. This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectedCommandProperty =DependencyProperty.Register("SelectedCommand", typeof(ICommand), typeof(DateTimePicker), new PropertyMetadata(null));public object SelectedCommandParameter{get { return (object)GetValue(SelectedCommandParameterProperty); }set { SetValue(SelectedCommandParameterProperty, value); }}// Using a DependencyProperty as the backing store for SelectedCommandParameter. This enables animation, styling, binding, etc...public static readonly DependencyProperty SelectedCommandParameterProperty =DependencyProperty.Register("SelectedCommandParameter", typeof(object), typeof(DateTimePicker), new PropertyMetadata(null));…………………………// 在需要調(diào)用的地方 調(diào)用此事件即可private void Button_Click(object sender, RoutedEventArgs e){// 命令的執(zhí)行SelectedCommand?.Execute(SelectedCommandParameter);}}
XAML代碼:
<c:DateTimePicker VerticalAlignment="Top" HorizontalAlignment="Center" SelectedCommand="{Binding SeletedCommand}" SelectedCommandParameter="{Binding}"/>
MVVM分層邏輯相關(guān)問題
VM邏輯中彈窗操作
需求:應(yīng)用中邏輯處理過程中需要打開一個子窗口,作為Dialog窗口進行信息顯示
利用一個第三方對象WindowProvider,允許View層進行窗口對象的注冊 ,允許ViewModel層進行窗口對象的調(diào)用請求
過程中涉及兩方的數(shù)據(jù)傳遞
第三方對象WindowProvider:
using System.Windows;namespace XH.Mvvm.Base
{public class WindowProvider{static Dictionary<string, WindowInfo> types = new Dictionary<string, WindowInfo>();// 收購窗口// 允許自定義名字 key,不自定義就是窗體名public static void Register<T>(string key = "",Window owner = null){if (string.IsNullOrEmpty(key))key = typeof(T).Name;if (!types.ContainsKey(key))types.Add(key, new WindowInfo { WinType = typeof(T),OwnerType = owner });}// 出售public static bool ShowDialog(string key,object dataContext){Type type = null;if (types.ContainsKey(key)){type = types[key].WinType;}if (type != null){// 同過反射創(chuàng)建新的對象Window win = (Window)Activator.CreateInstance(type);// 設(shè)置窗口所有者 當任務(wù)欄打開大窗口的時候,小窗口帶出win.Owner = types[key].OwnerType;win.DataContext = dataContext;bool state = (bool)win.ShowDialog();return state;}elsethrow new Exception("沒有找到對應(yīng)的彈窗對象");}}class WindowInfo{public Type WinType { get; set; }public Window OwnerType { get; set; }}
}
View地方調(diào)用:
public MainWindow(){InitializeComponent();WindowProvider.Register<SubWindow>(owner: this);}
ViewModel地方調(diào)用:
public MainViewModel()
{BtnCommand = new Command(obj =>{// Btn的執(zhí)行邏輯 打開子窗口// 因為不能View-->ViewModel-->View 來回調(diào)用,此方法不可取//new SubWindow().ShowDialog();SubViewModel subViewModel = new SubViewModel();subViewModel.Value = Value;if (WindowProvider.ShowDialog("SubWindow", subViewModel)){// 獲取到子窗口返回的Value屬性this.Value = subViewModel.Value;}else { }// 如何從子窗口返回到主窗口:SUbViewModel --> MainViewModel// 1、子窗口打開后,編輯完成,保存按鈕、取消按鈕// 2、最終數(shù)據(jù)不在子窗口處理,返回到主VM再處,保存、回退});
}
顯示:能夠順利顯示和傳值
邏輯:
- 收購
-
- 定義一個字典,然后記錄需要彈出的窗口信息(窗口名稱,父窗口)和key,用key和信息進行綁定,然后調(diào)用的時候用key調(diào)用窗口信息。
- 出售
-
- 如果存在這個key,然后同過反射把字典中的窗口信息反射出來給Window,然后進行設(shè)置Window的屬性,并且彈窗,同過DialogResult屬性來判斷是否需要寫入信息。
- 出售(調(diào)用)的時候,把需要傳入的Model通過參數(shù)傳進來。
- 調(diào)用
-
- 通過出售的時候返回的bool信息,來判斷是否需要保存下來返回的值
任意對象間邏輯調(diào)用
委托對象的管理,被動方進行委托方法的注冊,主動方進行委托方法的請求調(diào)用
核心 :委托對象的使用
ActionManager類:
namespace XH.Mvvm.Base
{public class ActionManager{static Dictionary<string, Delegate> types = new Dictionary<string, Delegate>();public static void Register<T>(Action<T> action, string key){if (!types.ContainsKey(key))types.Add(key, action);} public static void Register<T>(Func<T> action, string key){if (!types.ContainsKey(key))types.Add(key, action);}public static void Invoke<T>(string key, T arg){if (types.ContainsKey(key))((Action<T>)types[key]).Invoke(arg);}public static T InvokeWithResult<T>(string key){if (types.ContainsKey(key))return (types[key] as Func<T>).Invoke();return default(T);}}
}
A窗體進行訂閱:
public MainViewModel()
{// 訂閱的過程,ActionManager.Register<object>(new Action<object>(DoAction), "AAA");ActionManager.Register<object>(new Func<object>(DoFunc), "BBB");}private object DoFunc(){return this.Value;}private void DoAction(object obj){}
B窗體進行調(diào)用:
public SubViewModel()
{SubmitCommand = new Command(obj =>{// 發(fā)布的動作// B窗口傳遞給A窗口值A(chǔ)ctionManager.Invoke<object>("AAA",Value);// A窗口傳遞給B窗口值var v = ActionManager.InvokeWithResult<object>("BBB");});
}
邏輯:
- 注冊
-
- 注冊一個委托key字典,然后同過key和方法進行注冊,發(fā)布的時候同過key進行搜索委托事件執(zhí)行。
- 可以注冊Action 和 Func 方法,Action是調(diào)用的時候需要參數(shù),Func調(diào)用的時候是返回參數(shù)
- 注冊Func方法的時候,需要返回一個Object類型的參數(shù),給調(diào)用方
- 調(diào)用/發(fā)布
-
- 同過Key進行調(diào)用,但是需要傳入?yún)?shù),如果是Action的話,需要傳給注冊方一個object參數(shù),在注冊方的方法中。
- 如果是Func的話,返回一個參數(shù),是注冊方返回給掉用方的參數(shù)
注意:Func 和 Action 的區(qū)別
Func
- 定義:Func是一個泛型委托,用于表示可以帶有參數(shù)并且返回值的方法。Func委托可以有多個輸入?yún)?shù),但只能有一個返回值。
- 用途:通常用于需要執(zhí)行一個操作并返回結(jié)果的情況。例如,你可能需要一個方法來檢查某個字符串是否符合特定的格式,并返回一個布爾值表示檢查結(jié)果。
- 語法示例:
Func<T, TResult>
表示一個接受一個類型為T的參數(shù)并返回一個類型為TResult的結(jié)果的委托。Func<int, string, bool>
表示一個接受一個int類型和一個string類型參數(shù),并返回一個bool類型結(jié)果的委托。
Action
- 定義:Action是另一個泛型委托,但它不返回任何值(即返回類型為void)。Action委托可以有多個輸入?yún)?shù),但沒有返回值。
- 用途:適用于那些執(zhí)行操作但不需要返回結(jié)果的情況。例如,你可能需要一個方法來打印日志信息,或者更新某個對象的狀態(tài),這些操作都不需要返回值。
- 語法示例:
Action<T>
表示一個接受一個類型為T的參數(shù)但不返回任何結(jié)果的委托。Action<int, string>
表示一個接受一個int類型和一個string類型參數(shù),但不返回任何結(jié)果的委托。
Func和Action的主要區(qū)別歸納
特性 | Func | Action |
返回值 | 有返回值 | 無返回值(void) |
參數(shù)數(shù)量 | 可以有0到多個參數(shù) | 可以有0到多個參數(shù) |
用途 | 執(zhí)行操作并返回結(jié)果 | 執(zhí)行操作但不返回結(jié)果 |
語法示例 |
|
|
總結(jié)
Func和Action是編程中用于表示不同類型方法的泛型委托。Func用于表示需要返回值的方法,而Action用于表示不需要返回值的方法。它們的使用取決于你的具體需求,即在執(zhí)行某個操作時是否需要返回結(jié)果。通過合理使用Func和Action,可以使代碼更加清晰、靈活和易于維護。