Prism程序入口、View ViewModel關聯、數據綁定、數據校驗、cmd


Prism程序入口、View ViewModel關聯、數據綁定、數據校驗、cmd

這是一篇朝夕Jovan老師講Prism的課堂學習筆記。

關於Prism框架

Prism.Core:【Prism.dll】實現MVVM的核心功能,屬於一個與平台無關的項目

Prism.Wpf:【Prism.Wpf】包含了DialogService,Region,Module,Navigation,其他的一些WPF的功能

Prism.Unity:【Prism.Unity.Wpf】,IOC容器

Prism.Unity=>Prism.Wpf=>Prism.Core

創建啟動程序

第一種初始化方式:8.0版本以前只能使用PrismBootstrapper

  1. 添加啟動類:Bootstrapper
public class Bootstrapper : PrismBootstrapper
{
  protected override DependencyObject CreateShell()
  {        
      return Container.Resolve<FirstWindow>();
  }

  protected override void RegisterTypes(IContainerRegistry containerRegistry)
  {
      
  }
}
  1. 修改App.cs
public partial class App
{
	protected override void OnStartup(StartupEventArgs e)
  {
  base.OnStartup(e);

  var bs = new Bootstrapper();
  bs.Run();
  }  
}

第二種初始化方式:8.0版本開始提供一種新的方式PrismApplication【全局資源管控,項目啟動】

兩者類似,只不過把Bootstrapper類的東西,拿到App.cs實現

  1. App.xaml 中刪除程序的入口:StartupUrl="Main.xaml"
  2. App.xaml 中引入Prism名稱空間
<prism:PrismApplication x:Class="PrismLesson.App"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:local="clr-namespace:Zhaoxi.PrismLesson"
           xmlns:prism="http://prismlibrary.com/"
           >
  <Application.Resources>

  </Application.Resources>
</prism:PrismApplication>
  1. 修改App.cs,繼承PrismApplication,並重寫CreateShell方法
public partial class App : PrismApplication
{
  protected override Window CreateShell()
	{
  return Container.Resolve<FirstWindow>();
	}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
	{

	}
}

View與ViewModel的多種關聯方法

使用方法

  1. View中引入名稱空間:xmlns:prism="http://prismlibrary.com/"
  2. 設置為自動關聯:prism:ViewModelLocator.AutoWireViewModel="True"

注意事項:

  1. 必須是Views和ViewModels目錄
  2. 需要保證命名規范的正確性
    1. View可以以View結尾,也可以不寫。
    2. ViewModel必須以View的名稱+”ViewModel”進行命名

自定義ViewModel文件后綴規則

App.cs 中重寫ConfigureViewModelLocator方法

  1. View的名字
  2. 在那個名稱空間
  3. ViewModel的名字
protected override void ConfigureViewModelLocator()
{
    base.ConfigureViewModelLocator();

    //自定義ViewModel文件后綴,自動匹配
    //第一種方式
    //ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) => 
    //{
    	//兩個參數表示在那個名稱空間
    //    var viewName = viewType.FullName.Replace("YtViews","YtViewmodels");
    //    var viewAssemblyName = viewType.GetType().Assembly.FullName;
    //    var viewModelName = $"{viewName}VM,{viewAssemblyName}";    
    //    return Type.GetType(viewModelName);
    //});

    //一對一注冊的多種方式 01
    //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(),typeof(MainWindowViewModel));

    //02
    //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), 
    //    () =>Container.Resolve<MainWindowViewModel>()
    //);

    //03
    //ViewModeegisterlLocationProvider.R<MainWindow,M>();ainWindowViewModel
}

一對一注冊

三種代碼注冊方式:第三種方式最為簡潔,使用1對1注冊的時候,就可以取消掉prism:ViewModelLocator.AutoWireViewModel="True"

protected override void ConfigureViewModelLocator()
{
    base.ConfigureViewModelLocator();
    //01 第一種方式
    ViewModelLocationProvider.Register(typeof(FirstWindow).ToString(), typeof(FirstWindowVM));
      //02
    //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), 
    //    () =>Container.Resolve<MainWindowViewModel>()
    //);

    //03
    //ViewModelLocationProvider.Register<FirstWindow, FirstWindowVM>();   
}

Xaml注冊方式

  1. 引入命名空間:xmlns:vm="clr-namespace:Zhaoxi.PrismLesson.ZxViewModels"
  2. 設置關聯
<Window.DataContext>
    <prism:ContainerProvider Type="{x:Type vm:FirstWindowVM}"/>
</Window.DataContext>

MVVM數據屬性的多種方式

  1. 繼承BindableBase
  2. 實現數據綁定

第一種方式:RaisePropertyChanged()

public string MyProperty
{
    get { return myVar; }
    set
    {
        myVar = value;        
        //this.RaisePropertyChanged();
        //改變的時候通知其他屬性
        this.RaisePropertyChanged("其他屬性名稱");        
    }
}

第二種方式:SetProperty

寫了SetProperty,就可以刪除 myVar = value,因為ref.

//思考:為什么不直接在這里寫值改變后的處理,SetProperty方法內的回調對值是否改變做了判斷,只有真正改變了才會執行回調,直接寫SetProperty后面,則每次無論是否改變成功都會執行。

public string MyProperty
{
    get { return myVar; }
    set
    {       
        // 第二種方式
		//this.SetProperty(ref myVar, value, "MyProperty");
        
        //多了一個回調,變化之后調用
		this.SetProperty<string>(ref myVar, value,
    		() =>
    		{
        		//  onChanged
    		});

		//思考:為什么不直接在這里寫值改變后的處理,SetProperty方法內的回調對值是否改變做了判斷,只有真正改變了才會執行回調,直接寫SetProperty后面,則每次無論是否改變成功都會執行。
    }
}

MVVM數據驗證

  1. 繼承INotifyDataErrorInfo接口,實現接口:
public class FirstWindowVM : BindableBase, INotifyDataErrorInfo
{
    /// <summary>
    ///  INotifyDataErrorInfo 接口方法
    /// </summary>
    //
    //錯誤變化 錯誤屬性中調用這個事件    
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    //檢查是否有錯誤
    public bool HasErrors => ErrorsContainer.HasErrors;
   	//獲取錯誤
    public IEnumerable GetErrors(string propertyName) => ErrorsContainer.GetErrors(propertyName);
}
  1. 實現一個ErrorsContainer屬性
//OnPropertyChanged;
//    CanExecuteChanged;
private ErrorsContainer<string> errorsContainer;

public ErrorsContainer<string> ErrorsContainer
{
    get
    {
        if (errorsContainer == null)
            errorsContainer = new ErrorsContainer<string>((propName) =>
            {
                // 異常信息的處理
                ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propName));
            });

        return errorsContainer;
    }
    set { errorsContainer = value; }
}
  1. 對數據進行錯誤處理
public string MyProperty
{
    get { return myVar; }
    set
    {
        this.SetProperty(ref myVar, value, "MyProperty");

        if (value == "1231")
        {
            // 異常消息
            ErrorsContainer.SetErrors("MyProperty", new string[] { "輸入值無效1231231" });
        }
        else
        {
            ErrorsContainer.ClearErrors("MyProperty");
        }
    }
}
  1. UI錯誤提示樣式
<Window.Resources>
    <ControlTemplate TargetType="{x:Type TextBox}" x:Key="ct">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>
                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
                CornerRadius="5">
                    <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
                          VerticalContentAlignment="Center" Margin="3,5" BorderThickness="0"/>
                </Border>

                <TextBlock Grid.Row="1" Text="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox,Mode=FindAncestor}}" 
                   Foreground="Red" Margin="10,5"
                   Name="txtError"/>

            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Visibility" Value="Visible" TargetName="txtError"/>
                    <Setter Property="ToolTip" 
                    Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
</Window.Resources>
<Grid>
    <StackPanel Margin="30">
        <TextBox Text="{Binding MyProperty,UpdateSourceTrigger=PropertyChanged}" FontSize="30"
                 Template="{StaticResource ct}"/>
        <TextBlock Text="{Binding MyProperty}" FontSize="30"/>
    </StackPanel>
</Grid>

MVVM命令的多種方式

語法糖

  1. cmd 基本使用
private DelegateCommand _fieldName;
public DelegateCommand CommandName =>
    _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName));

void ExecuteCommandName()
{

}
  1. cmdfull
private DelegateCommand _fieldName;
public DelegateCommand CommandName =>
    _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName, CanExecuteCommandName));

void ExecuteCommandName()
{

}
bool CanExecuteCommandName()
{
    return true;
}

  1. cmdg
private DelegateCommand<string> _fieldName;
public DelegateCommand<string> CommandName =>
    _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName));

void ExecuteCommandName(string parameter)
{

}
  1. cmdgfull
private DelegateCommand<string> _fieldName;
public DelegateCommand<string> CommandName =>
    _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName, CanExecuteCommandName));

void ExecuteCommandName(string parameter)
{

}

bool CanExecuteCommandName(string parameter)
{
    return true;
}

基礎使用

傳統方式掛載執行委托、檢查可執行委托。

默認直接執行cmd

  1. 繼承基類DelegateCommand
  2. 實現命令屬性
private DelegateCommand _changeValue;
public DelegateCommand ChangeValue
{
    get
    {
        if (_changeValue == null)
    		_changeValue = new DelegateCommand(DoChangeValue);
        return _changeValue;
    }
    set{_changeValue = value;}
}
private void DoChangeValue()
{
    this.Value == "1231";
}

默認判斷是否執行cmd

IsCan為true,才可以執行命令。

private DelegateCommand _changeValue;
public DelegateCommand ChangeValue
{
    get
    {
        if (_changeValue == null)
    		_changeValue = new DelegateCommand(DoChangeValue, DoCanChangeValue);
        return _changeValue;
    }
    set{_changeValue = value;}
}
// 判斷命令相關按鈕是否可執行
private bool DoCanChangeValue()
{
    return IsCan;
}

// 命令執行體
private void DoChangeValue(string param)
{
    this.Value = "456";
}

private bool _isCan;

public bool IsCan
{
    get { return _isCan; }
    set
    {
        SetProperty(ref _isCan, value);
        ChangeValue.RaiseCanExecuteChanged();
    }
} 

監控屬性變化,執行cmd

  1. 監控某個屬性是否變化,如果變化出發cmd。

  2. 使用DelegateCommand對象的ObservesProperty方法,不需要ChangeValue.RaiseCanExecuteChanged()。

ObservesCanExecute監控的是某個屬性的變化,而不是某個值。屬性變化的時候Prism內部觸發了ChangeValue.RaiseCanExecuteChanged()

精簡版

if (_changeValue == null)
{
    _changeValue = new DelegateCommand(DoChangeValue, DoCanChangeValue);     
    //觀察一個屬性,當這個屬性變化的時候觸發DoCanChangeValue
    _changeValue.ObservesProperty(() => Value);
}

詳細版

private string _value;
public string Value
{
    get { return _value; }
    set { SetProperty<string>(ref _value, value); }
}

private DelegateCommand _changeValue;
public DelegateCommand ChangeValue
{
    get
    {
        if (_changeValue == null)
        {
            _changeValue = new DelegateCommand(DoChangeValue,DoCanChangeValue).ObservesCanExecute(() => Value);
        }

        return _changeValue;
    }
}

//判斷命令相關按鈕是否可執行
private bool DoCanChangeValue()
{
    return IsCan;    
}

//命令執行體
private void DoChangeValue()
{
    this.Value = "456";
}

private string _value;

public string Value
{
    get { return _value; }
    set { SetProperty<string>(ref _value, value); }
}

監控屬性是否為true,執行cmd,可以省略大量代碼,但有局限性。

通過ObservesCanExecute觀察屬性是否為true,如果為true則執行cmd.可以刪除DoCanChangeValue回調。

簡化了DoCanChangeValue,但是功能性少了多了局限性。

精簡版

if (_changeValue == null)
{
    _changeValue = new DelegateCommand(DoChangeValue);
    _changeValue.ObservesCanExecute(() => IsCan);
}

詳細版

private string _value;
public string Value
{
    get { return _value; }
    set { SetProperty<string>(ref _value, value); }
}

private DelegateCommand _changeValue;
public DelegateCommand ChangeValue
{
    get
    {
        if (_changeValue == null)
        {
            _changeValue = new DelegateCommand(DoChangeValue).ObservesCanExecute(() => IsCan);
        }
        return _changeValue;
    }
}

//命令執行體
private void DoChangeValue()
{
    this.Value = "456";
}

private bool _isCan;

public bool IsCan
{
    get { return _isCan; }
    set
    {
        SetProperty(ref _isCan, value);
    }
}

帶參數的cmd

int型,Prism會有錯誤提示,MvvmLight沒有提示。

簡化版

private DelegateCommand<string> _changeValue;
public DelegateCommand<string> ChangeValue
{
    get
    {
         if (_changeValue == null)
         {
             _changeValue = new DelegateCommand<string>(DoChangeValue);
             _changeValue.ObservesCanExecute(() => IsCan);
         }

         return _changeValue;
     }
 }

//普通
private void DoChangeValue(string param)
{
    this.Value = "456";
}

if (_changeValue == null)
{
    _changeValue = new DelegateCommand<string>(DoChangeValue);
    _changeValue.ObservesCanExecute(() => IsCan);
}
<Button Content="Button" FontSize="30" Command="{Binding ChangeValue}" CommandParameter="123"/>

普通詳細版

private string _value;
public string Value
{
    get { return _value; }
    set { SetProperty<string>(ref _value, value); }
}

private DelegateCommand<string> _changeValue;
public DelegateCommand<string> ChangeValue
{
    get
    {
        if (_changeValue == null)
        {
            _changeValue = new DelegateCommand<string>		(DoChangeValue).ObservesCanExecute(() => IsCan);
        return _changeValue;
    }
}

//命令執行體
private void DoChangeValue(string param)
{
    this.Value = "param";
}

private bool _isCan;

public bool IsCan
{
    get { return _isCan; }
    set
    {
        SetProperty(ref _isCan, value);
    }
}

異步命令

簡化版

//異步
if (_changeValue == null)
{
    _changeValue = new DelegateCommand<string>(async (o) => await DoChangeValue(o));
    _changeValue.ObservesCanExecute(() => IsCan);
}

private async Task DoChangeValue(string param)
{
    await Task.Delay(1000);
    this.Value = "456";
}

詳細版

private string _value;
public string Value
{
    get { return _value; }
    set { SetProperty<string>(ref _value, value); }
}

private DelegateCommand<string> _changeValue;
public DelegateCommand<string> ChangeValue
{
    get
    {
        if (_changeValue == null)
        {
            _changeValue = new DelegateCommand<string>(async (param) => await DoChangeValue(param)).ObservesCanExecute(() => IsCan);

        return _changeValue;
    }
}

//命令執行體
private async Task DoChangeValue(string param)
{
    await Task.Delay(1000);
    this.Value = "param";
}

private bool _isCan;

public bool IsCan
{
    get { return _isCan; }
    set
    {
        SetProperty(ref _isCan, value);
    }
}

事件綁定Command,事件參數傳值

  1. 引用Interactivity\Interaction兩個庫中的一個,Prism默認繼承Interactivity\Interaction庫,xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

  2. 一般不會在Button中使用,實際是向沒有Command屬性的對象事件進行綁定,例如TextBox。

  3. 參數類型:如果是Source就是把事件源對象傳進來,還有多種參數類型可以F12跟進去看函數定義。

  4. 傳遞事件常見的e參數:刪除TriggerParameterPath,默認傳遞的就是e參數

<TextBox FontSize="30" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="TextChanged">
            <!--  如果需要傳EventArgs參數的話,可以將TriggerParameterPath移除,不指定  -->
            <prism:InvokeCommandAction Command="{Binding EventCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

xaml

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

<Button Content="Button - Event" FontSize="30">
    <!--利用Button的Click事件做演示,實際是向沒有Command屬性的對象事件進行綁定-->
    <!--Interactivity\Interaction-->
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <!--如果需要傳EventArgs參數的話,可以將TriggerParameterPath移除,不指定-->
            <prism:InvokeCommandAction Command="{Binding EventCommand}"/>
            <!--<prism:InvokeCommandAction Command="{Binding EventCommand}" TriggerParameterPath="Source"/>-->

        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>
private DelegateCommand<object> _eventCommand;

public DelegateCommand<object> EventCommand
{
    get
    {
        if (_eventCommand == null)
        {
            _eventCommand = new DelegateCommand<object>((o) =>
            {
				//接收到的事件參數
            });
        }
        return _eventCommand;
    }
}

事件聚合器、彈出自定義窗口

精簡版

事件訂閱、發布的一個過程。

  1. 定義一個基本消息類型MessageEvent,繼承PubSubEvent
  2. 聲明IEventAggregator 類型字段
  3. 構造函數中注入一個IEventAggregator
  4. 訂閱消息事件

執行命令以后,事件執行。

主要是通過 _ea.GetEvent<PubSubEvent >().Subscribe(DoMessage);中的PubSubEvent 判斷的,所以才需要創建單獨的類,甚至是空類,主要是為了方便區分。

public class MessageEvent : PubSubEvent<string>
{
}
IEventAggregator _ea;

public FirstWindowViewModel(IEventAggregator ea)
{
    this.Value = "123";

    _ea = ea;
    // 訂閱一個消息事件
    _ea.GetEvent<PubSubEvent<string>>().Subscribe(DoMessage);
}

private void DoMessage(string msg)
{
    
}

private DelegateCommand _eventCommand;

public DelegateCommand EventCommand
{
    get
    {
        if (_eventCommand == null)
        {
            _eventCommand = new DelegateCommand<object>(() =>
            {
                //彈出窗口
                //自定義窗口
                //發布
                _ea.GetEvent<PubSubEvent<string>>().Publish("123");
            });
        }
       return _eventCommand;
    }
}

keepSubscriberReferenceAlive參數控制是否為弱引用

keepSubscriberReferenceAlive:訂閱事件屬於一個弱引用。

  1. 如果是false,不需要管取消訂閱,默認為false.
  2. 如果是true,手動處理取消訂閱
ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1,keepSubscriberReferenceAlive: false);

// 取消訂立,如果 keepSubscriberReferenceAlive 為False或默認值 不需要取消訂閱
//ea.GetEvent<MessageEvent1>().Unsubscribe(DoMessage1);
ThreadOption.PublisherThread參數控制線程的
  1. PublisherThread = 0, 默認是PublisherThread

  2. UIThread = 1,

  3. BackgroundThread = 2

ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false);
Predicate 對消息進行過濾Filter

對發布的事件傳過來的參數進行過濾,滿足要求的才會出發事件。

ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false, DoFilter);

private bool DoFilter(string msg)
{
    return msg.Contains("12");
}

詳細版

xaml代碼

<Button
        Command="{Binding Command}"
        CommandParameter="123"
        Content="Button 事件聚合觸發"
        FontSize="30" />
<ItemsControl FontSize="30" ItemsSource="{Binding ValueList}" />

01 繼承PubSubEvent

public class MessageEvent : PubSubEvent<string>
{
    public int MyProperty { get; set; }
}

public class MessageEvent1 : PubSubEvent<string>
{
}

02 訂閱

private ObservableCollection<string> _valueList;

public ObservableCollection<string> ValueList
{
    get { return _valueList ?? (_valueList = new ObservableCollection<string>()); }
    set { _valueList = value; }
}


IEventAggregator _ea;
public FirstWindowViewModel(IEventAggregator ea, IContainerExtension containerRegistry)
{
    this.Value = "123";

    _ea = ea;
    // 訂閱一個消息事件
    //ea.GetEvent<PubSubEvent<string>>().Subscribe(DoMessage);
    var me = ea.GetEvent<MessageEvent>();
    me.Subscribe(DoMessage);
    me.MyProperty = 123;

    /// ThreadOption,,默認PublisherThread,管理訂立消息的執行線程
    /// keepSubscriberReferenceAlive:訂閱事件屬於一個弱引用
    /// Filter  消息過濾 ,如果回調返回True,才執行消息體,否則不處理此消息
    //ThreadOption.PublisherThread控制線程的,本案例中配合ValueList和ItemsControl
    ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false, DoFilter);

    //指定在UI線程執行
    //ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.UIThread, keepSubscriberReferenceAlive: false, DoFilter);
    // 取消訂立,如果 keepSubscriberReferenceAlive 為False或默認值 不需要取消訂閱
    //ea.GetEvent<MessageEvent1>().Unsubscribe(DoMessage1);
}

private void DoMessage(string msg)
{

}
//UI線程執行
//private void DoMessage(string msg)
//{
	//ValueList.Add("123");
//}

private bool DoFilter(string msg)
{
    return msg.Contains("12");
}

03 發布

private DelegateCommand _command;

public DelegateCommand Command
{
    get
    {
        if (_command == null)
        {
            _command = new DelegateCommand(() =>
            {
                // 彈出窗口
                // 通過事件聚合器彈出自定義窗口
                // 而不是普通的類似MvvmLight中的 Messenger  Token   Type

                //_ea.GetEvent<PubSubEvent<string>>().Publish("123");
                //_ea.GetEvent<MessageEvent>().Publish("123");

                
                var value = _ea.GetEvent<MessageEvent>().MyProperty;
                _ea.GetEvent<MessageEvent1>().Publish("123");
                _ea.GetEvent<MessageEvent1>().Publish("456");
                _ea.GetEvent<MessageEvent1>().Publish("123");
                //Task.Run(() =>
                //{
                //    _ea.GetEvent<MessageEvent1>().Publish("123");
                //});
            });
        }
        return _command;
    }
}

復合命令

一個按鈕,把所有相同的復合命令執行一遍。比如:保存按鈕,把所有內容保存。

每個頁面出發單獨的保存,還有個隱藏功能,所有的命令都有個是否可執行的方法,如果設置了,那么只有所有按鈕都可以執行以后,它才可以執行。

  1. 添加一個程序集,需要我們自定義一個接口,把它改成類庫。這樣復合命令就實現好了
public interface ICompositeCommands
{
    CompositeCommand DoCommand { get; }
}

public class CompositeCommands : ICompositeCommands
{
    private CompositeCommand _doCommand = new CompositeCommand();
    public CompositeCommand DoCommand
    {
        get { return _doCommand; }
    }
}
  1. App.xaml.cs中的RegisterTypes 注入
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // 注冊復合命令
    containerRegistry.RegisterSingleton<ICompositeCommands, CompositeCommands>();
}
  1. 創建一個按鈕,xaml
<Grid>
    <StackPanel>
        <TextBlock Text="HeaderView" FontSize="30"/>
        <Button Content="Button" FontSize="30" Command="{Binding CompositeCommands.DoCommand}"/>
    </StackPanel>
</Grid>
  1. 創建對應的ViewModule
public class HeaderViewModel : BindableBase
{
    private ICompositeCommands _compositeCommand;

    public ICompositeCommands CompositeCommands
    {
        get { return _compositeCommand; }
        set { SetProperty(ref _compositeCommand, value); }
    }

    public HeaderViewModel(ICompositeCommands compositeCommands)
    {
        CompositeCommands = compositeCommands;
    }
}
  1. 構造函數注入ICompositeCommands,將command注冊到復合命令集合中。
public DelegateCommand SaveCommand { get; private set; } 
public MenuManagementViewModel(ICompositeCommands compositeCommands)
{
     SaveCommand = new DelegateCommand(() =>
        {
            // 菜單保存
        });
	 compositeCommands.DoCommand.RegisterCommand(SaveCommand);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM