Prism.WPF -- Prism框架使用(下)

本文參考Prism官方示例git

命令使用

Prism提供了兩種命令:DelegateCommand和CompositeCommand。github

DelegateCommand

DelegateCommand封裝了兩個委託:Execute和CanExecute,使用以下:app

// view
<Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand"/>

// viewmodel
public DelegateCommand ExecuteDelegateCommand { get; private set; }

public MainWindowViewModel()
{
    ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
}

private void Execute()
{
    UpdateText = $"Updated: {DateTime.Now}";
}

private bool CanExecute()
{
    return IsEnabled;
}
CompositeCommand

CompositeCommand爲複合命令,由多個子命令構成。當調用CompositeCommand時,將依次調用每一個子命令。默認狀況下,當全部子命令CanExecute均返回true時纔會執行CompositeCommand。使用方法以下:ide

// Project.Core中定義接口及實現
public interface IApplicationCommands
{
    CompositeCommand SaveCommand { get; }
}

public class ApplicationCommands : IApplicationCommands
{
    private CompositeCommand _saveCommand = new CompositeCommand();
    public CompositeCommand SaveCommand
    {
        get { return _saveCommand; }
    }
}

// App.xaml.cs中註冊單例對象
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterSingleton<
        IApplicationCommands, ApplicationCommands>();
}

// viewmodel中添加子命令
public TabViewModel(IApplicationCommands applicationCommands)
{
    _applicationCommands = applicationCommands;

    UpdateCommand = new DelegateCommand(Update).ObservesCanExecute(
        () => CanUpdate);

    _applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
}

// view中執行命令(需在對應的viewmodel的構造函數中傳入IApplicationCommands實例)
<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>

EventAggregator

EventAggregator是一種事件機制,解決了鬆耦合模塊間的通訊問題。使用方法以下:函數

// Project.core中聲明事件類型
public class MessageSentEvent : PubSubEvent<string>
{
}

// viewmodel中發佈事件
IEventAggregator _ea;
public MessageViewModel(IEventAggregator ea)
{
    _ea = ea;
    // 發佈事件的命令
    SendMessageCommand = new DelegateCommand(SendMessage);
}

private void SendMessage()
{
    _ea.GetEvent<MessageSentEvent>().Publish(Message);
}

// viewmodel中訂閱事件
IEventAggregator _ea;
public MessageListViewModel(IEventAggregator ea)
{
    _ea = ea;
    _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
    // 以下方式能夠過濾事件,可經過第二個參數指定處理線程
    // _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived, 
        ThreadOption.PublisherThread, false, 
        (filter) => filter.Contains("Brian"));
}

private void MessageReceived(string message)
{
    // hava a message
}

RegionNavigation

區別於View Discovery和View Injection,RegionNavigation可經過region名稱與要導航的視圖名稱實現更通用的視圖導航功能,使用以下:線程

// 模塊類中註冊導航視圖
public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<ViewA>();
}

// xaml導航命令
<Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" >Navigate to View A</Button>

// viewmodel實現導航
public DelegateCommand<string> NavigateCommand { get; private set; }

public MainWindowViewModel(IRegionManager regionManager)
{
    _regionManager = regionManager;
    NavigateCommand = new DelegateCommand<string>(Navigate);
}

private void Navigate(string navigatePath)
{
    if (navigatePath != null)
        _regionManager.RequestNavigate("ContentRegion", 
            navigatePath, NavigationCompleted);
}

// 可指定導航完成回調
private void NavigationCompleted(NavigationResult result)
{
    // ...
}
INavigationAware接口

INavigationAware接口包含三個方法:OnNavigatedFrom、OnNavigatedTo、IsNavigationTarge。當ViewAViewModel及ViewBViewModel均實現了INavigationAware接口,ViewA導航到ViewB時,先調用ViewA的OnNavigatedFrom方法,而後調用ViewB的IsNavigationTarge,當其返回true時,調用OnNavigatedTo方法,若IsNavigationTarge返回false,建立新ViewB。示例以下:code

public class ViewAViewModel : BindableBase, INavigationAware
{
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        // ...
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
        // ...
    }
}
IConfirmNavigationRequest接口

IConfirmNavigationRequest接口繼承了INavigationAware接口,並添加了ConfirmNavigationRequest方法。若ViewAViewModel實現了IConfirmNavigationRequest接口,當ViewA導航到ViewB時,先調用ConfirmNavigationRequest方法,若continuationCallback()參數爲true,將繼續執行導航,執行OnNavigatedFrom方法;若continuationCallback()參數爲false,中止導航。示例以下:對象

public class ViewAViewModel : BindableBase, IConfirmNavigationRequest
{
    public void ConfirmNavigationRequest(NavigationContext navigationContext, 
        Action<bool> continuationCallback)
    {
        bool result = true;

        if (MessageBox.Show("Do you to navigate?", "Navigate?", 
            MessageBoxButton.YesNo) == MessageBoxResult.No)
            result = false;

        continuationCallback(result);
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {  
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
    }
}
IRegionMemberLifetime接口

IRegionMemberLifetime接口只包含一個KeepAlive只讀屬性。其默認值爲true,若其爲false,則當該region導航到其它視圖時,實現了該接口的當前視圖將從IRegion.Views集合中移除並回收。若爲true,即便導航到其它視圖,該視圖依然存在於IRegion.Views集合。示例以下:繼承

public class ViewAViewModel : BindableBase, IRegionMemberLifetime
{
    public bool KeepAlive
    {
        get
        {
            return false;
        }
    }
}
參數傳遞

可以使用NavigationParameters實現導航時的參數傳遞,使用方法以下:接口

// 導航命令
private void PersonSelected(Person person)
{
    var parameters = new NavigationParameters();
    parameters.Add("person", person);

    if (person != null)
        _regionManager.RequestNavigate("PersonDetailsRegion", 
            "PersonDetail", parameters);
}

// 參數處理
public void OnNavigatedTo(NavigationContext navigationContext)
{
    var person = navigationContext.Parameters["person"] as Person;
    // ...
}

public bool IsNavigationTarget(NavigationContext navigationContext)
{
    var person = navigationContext.Parameters["person"] as Person;
    // ...
}
Navigation Journal

Navigation Journal能夠記錄導航的過程,其經過IRegionNavigationJournal接口實現。經過Navigation Journal,能夠實現向前/向後導航。示例以下:

// GoForward
public class PersonListViewModel : BindableBase, INavigationAware
{
    IRegionNavigationJournal _journal;
    public DelegateCommand GoForwardCommand { get; set; }

    public PersonListViewModel(IRegionManager regionManager)
    {
        ...
        GoForwardCommand = new DelegateCommand(GoForward, CanGoForward);
    }

    // IRegionNavigationJournal.GoBack到行至此
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        _journal = navigationContext.NavigationService.Journal;
        GoForwardCommand.RaiseCanExecuteChanged();
    }

    private void GoForward()
    {
        _journal.GoForward();
    }

    private bool CanGoForward()
    {
        return _journal != null && _journal.CanGoForward;
    }
}

// GoBack
public class PersonDetailViewModel : BindableBase, INavigationAware
{
    IRegionNavigationJournal _journal;
    public DelegateCommand GoBackCommand { get; set; }

    public PersonDetailViewModel()
    {
        GoBackCommand = new DelegateCommand(GoBack);
    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        _journal = navigationContext.NavigationService.Journal;
    }

    private void GoBack()
    {
        _journal.GoBack();
    }
}

InvokeCommandAction

Prism提供了InvokeCommandAction以使ViewModel處理View的事件,示例以下:

// view xaml
<ListBox ItemsSource="{Binding Items}" SelectionMode="Single">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <prism:InvokeCommandAction Command="{Binding SelectedCommand}" 
                TriggerParameterPath="AddedItems" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

// viewmodel
public DelegateCommand<object[]> SelectedCommand { get; private set; }

public MainWindowViewModel()
{
    ...
    SelectedCommand = new DelegateCommand<object[]>(OnItemSelected);
}

private void OnItemSelected(object[] selectedItems)
{
    if (selectedItems != null && selectedItems.Count() > 0)
        SelectedItemText = selectedItems.FirstOrDefault().ToString();
}
相關文章
相關標籤/搜索