乐趣区

关于WPF:PrismWPF-Prism框架使用下

本文参考 Prism 官网示例

命令应用

Prism 提供了两种命令:DelegateCommand 和 CompositeCommand。

DelegateCommand

DelegateCommand 封装了两个委托:Execute 和 CanExecute,应用如下:

// 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。应用办法如下:

// 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。示例如下:

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();
}
退出移动版