5.2 自定义弹窗

1. 背景

在Prism中,可以使用交互请求对象实现弹出窗口行为,系统提供默认的通知弹窗和确认弹窗,同时允许自定义弹窗。这里使用MVVM模式实现自定义弹窗。

2. 实现

2.1 ViewModel

为了实现自定义弹窗,ViewModel类需要继承IInteractionRequestAware,该接口包含两个属性Notification和FinishInteraction属性,代表需要传入窗口的内容以及完成交互行为。实现两个属性即可。示例如下:

using System;
using Prism.Interactivity.InteractionRequest;
using Prism.Mvvm;
using System.Windows.Input;
using Prism.Commands;

namespace AutoSeller.Modules.Manager.ViewModels
{
    public class CreateDrugViewModel : BindableBase, IInteractionRequestAware
    {
        public ICommand ConfirmCmd { get;private set; }
        public ICommand CancelCmd { get;private set; }

        private IConfirmation _confirmation;
        public INotification Notification
        {
            get
            {
                return _confirmation;
            }
            set
            {
                SetProperty(ref _confirmation,(IConfirmation) value);
            }
        }
        public Action FinishInteraction { get; set; }

        public CreateDrugViewModel()
        {
            ConfirmCmd = new DelegateCommand(Confirm);
            CancelCmd = new DelegateCommand(Cancel);
        }

        private void Cancel()
        {
            _confirmation.Confirmed = false;
            FinishInteraction?.Invoke();
        }

        private void Confirm()
        {
            _confirmation.Confirmed = true;
            FinishInteraction?.Invoke();
        }
    }
}

在完成Notification属性时记得执行强制类型转换。当程序运行时会自动执行两个属性的set操作。

2.1 View

虽然是一个弹窗,View不能定义为一个窗口,应为UserControl。在该窗口展示需要实现的内容。

UserControl x:Class="AutoSeller.Modules.Manager.Views.CreateDrugView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AutoSeller.Modules.Manager.Views"
             xmlns:prism="http://prismlibrary.com/"
             mc:Ignorable="d" 
             Width="300"
             Height="300"
             prism:ViewModelLocator.AutoWireViewModel="True"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Title}"/>
        <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="药品唯一编号"/>
                <TextBox Text="{Binding Notification.Content.DrugCode}"
                           MinWidth="100" HorizontalAlignment="Stretch"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="药品名称"/>
                <TextBox Text="{Binding Notification.Content.DrugName}"
                           MinWidth="100" HorizontalAlignment="Stretch"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="生产厂家"/>
                <TextBox Text="{Binding Notification.Content.DrugFactory}"
                           MinWidth="100" HorizontalAlignment="Stretch"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Grid.Row="2" Orientation="Horizontal"
                    HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="确认" Command="{Binding ConfirmCmd}"/>
            <Button Content="取消" Command="{Binding CancelCmd}"/>
        </StackPanel>
    </Grid>
</UserControl>

Prism有一个很奇怪的地方是不能通过属性注入方式为View绑定ViewModel,只能使用自动连接方式,如下:

prism:ViewModelLocator.AutoWireViewModel="True"

2.4 注册

定义完自定义弹窗后我们不需要手动在DI容器中注册,Prism规则是只要引用该自定义弹窗的窗口注册后该自定义弹窗就自动注册了。

3. 使用

3.1. 准备窗口

需要在View层准备窗口,使用时需要借助Blend的Interactivity对象对象交互触发器InteractionRequestTrigger,Prism的默认弹出窗口仅包含标题,确认按钮及一行文字,如果需要实现自定义弹窗,需要将为PopupWindowAction的WindowContent属性赋自定义view,如下:

<UserControl x:Class="AutoSeller.Modules.Manager.Views.MedicineMgrView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:AutoSeller.Modules.Manager.Views"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:prism="http://prismlibrary.com/"
             mc:Ignorable="d" 
             d:DesignHeight="600" d:DesignWidth="400">
    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding CreateDrugPopup}">
            <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True">
                <prism:PopupWindowAction.WindowContent>
                    <local:CreateDrugView/>
                </prism:PopupWindowAction.WindowContent>
            </prism:PopupWindowAction>
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>
</UserControl>

无边框弹窗

有时我们不希望弹窗有标题栏,通过设定弹出对象的WindowStyle可以实现该功能,

<prism:InteractionRequestTrigger SourceObject="{Binding SendBackBoxPopup}">
    <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True"
                             WindowStyle="{StaticResource IronPopup}">
        <prism:PopupWindowAction.WindowContent>
            <operate:SendBackBoxView />
        </prism:PopupWindowAction.WindowContent>
    </prism:PopupWindowAction>
</prism:InteractionRequestTrigger>

在样式文件中定义静态资源IronPopup

<Style x:Key="IronPopup" TargetType="Window">
    <Setter Property="WindowStyle" Value="None"/>
    <Setter Property="SizeToContent" Value="WidthAndHeight"/>
</Style>

3.1 激活窗口

激活窗口简单,在ViewModel层定义InteractionRequest即可,

using Prism.Commands;
using Prism.Interactivity.InteractionRequest;
namespace AutoSeller.Modules.Manager.ViewModels
{
    public class MedicineMgrViewModel
    {
        public ICommand CreateCmd { get; private set; }
        public InteractionRequest<IConfirmation> CreateDrugPopup { get; private set; }
        public MedicineMgrViewModel()
        {
            CreateCmd = new DelegateCommand(Create);
            CreateDrugPopup = new InteractionRequest<IConfirmation>();
        }
        
        private void Create()
        {
            var drug = new DrugInfo();
            //说明:目前暂时不确定使用药品唯一编号还是其他
            //drug.DrugCode = Guid.NewGuid().ToString();
            CreateDrugPopup.Raise(new Confirmation { Title = @"新建药品", Content = drug }, t => {
                if (t.Confirmed)
                {
                    Create((DrugInfo)t.Content);
                }
            });
        
    }
}
posted @ 2020-11-01 23:19  饮冰少年  阅读(303)  评论(0编辑  收藏  举报