[Prism]如何在主程序中合理的弹出子窗体

#以前写过的一篇博文,里面介绍的方法,在实际项目里频繁使用,分享至此


说起子窗体,大家都会想到ChildWindow,多熟悉的一个控件。不错,Sliverlight中已经提供了子窗体的具体实现,而在WPF中却没有这么好的事情(有的第三方控件商已经提供此控件)。最常见的实现方法就是在ViewModel中,直接New ChildWindow,然后直接Show。这样的方法也达到的要求。但是它不符合MVVM分层思想,再就是代码不美观,难以维护,今天我就给大家介绍一种美观又实用的方法。


原理


通过Prism中提供的InteractionRequestTrigger事件触发器,实现点击按钮或者用户的某种操作弹出对话框的效果。另外,不要忘了引用此命名空间:

using Microsoft.Practices.Prism.Interactivity.InteractionRequest;

创建ChildWindow窗体

<Window x:Class="ChildWindowDemo.ChildWindow.ChildWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        Width="300" Height="150" 
        Title="{Binding Title}"
        x:Name="confirmationWindow" Topmost="True" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ContentControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Content="{Binding Content}"/>

        <Button Content="Cancel" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding ElementName=confirmationWindow}" MethodName="Close"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button Content="OK" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:ChangePropertyAction PropertyName="Confirmed" TargetObject="{Binding}" Value="True"/>
                    <ei:CallMethodAction TargetObject="{Binding ElementName=confirmationWindow}" MethodName="Close"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</Window>

创建ChildWindow的基类


新建类:ChildWindowActionBase 并从TriggerAction<T>派生,代码如下:

public class ChildWindowActionBase : TriggerAction<FrameworkElement>
    {
        protected override void Invoke(object parameter)
        {
            var arg = parameter as InteractionRequestedEventArgs;
            if (arg == null)
                return;

            var windows = this.GetChildWindow(arg.Context);

            var callback = arg.Callback;
            EventHandler handler = null;
            handler =
                (o, e) =>
                {
                    windows.Closed -= handler;
                    callback();
                };
            windows.Closed += handler;

            windows.ShowDialog();

        }

        Window GetChildWindow(Notification notification)
        {
            var childWindow = this.CreateDefaultWindow(notification);
            childWindow.DataContext = notification;

            return childWindow;
        }

        Window CreateDefaultWindow(Notification notification)
        {
            return (Window)new ChildWindow.ChildWindow();
        }
    }   

如何调用


主程序界面代码如下:

<Window x:Class="ChildWindowDemo.MainWindow"
        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:prism="http://www.codeplex.com/prism"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:local="clr-namespace:ChildWindowDemo"
        Title="MainWindow" Height="200" Width="300">
    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}">
            <local:ChildWindowActionBase/>
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Button Command="{Binding RaiseConfirmation}" Content="Click Me !" HorizontalAlignment="Left" Margin="29,31,0,0" VerticalAlignment="Top" Width="217" Height="55"/>
        <TextBlock HorizontalAlignment="Left" Margin="29,106,0,0" TextWrapping="Wrap" Text="{Binding ConfirmationResult}" VerticalAlignment="Top"/>
    </Grid>
</Window>

对之对应的ViewModel:

public class MainWindowViewModel : NotificationObject
    {
        public MainWindowViewModel()
        {
            this.RaiseConfirmation = new DelegateCommand(this.OnRaiseConfirmation);
            this.ConfirmationRequest = new InteractionRequest<Confirmation>();
        }

        public InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }

        public DelegateCommand RaiseConfirmation { get; private set; }

        private string result;
        public string ConfirmationResult
        {
            get { return result; }
            set
            {
                result = value;
                this.RaisePropertyChanged(() => this.ConfirmationResult);
            }
        }

        private void OnRaiseConfirmation()
        {
            this.ConfirmationRequest.Raise(
                new Confirmation { Content = "是否确认", Title = "子窗体" },
                (cb) => { ConfirmationResult = cb.Confirmed ? "确认" : "取消"; });
        }      
    }

总结


这样的写法比较符合MVVM的分层思想,子窗体可以随心定制,而不需要去改逻辑层的代码。具体代码以上全部提供,谢谢。

你可能感兴趣的:(.net,command,WPF,MVVM)