Prism技巧

Prism 8.0

Prism一般架构

using Prism.DryIoc;
using DryIoc.Microsoft.DependencyInjection;
using HandyControl;
using Microsoft.Extensions.Http;

protected override Window CreateShell()
{
    return Container.Resolve<MainWindow>();
}
protected override IContainerExtension CreateContainerExtension()
{
    var services = MicrosoftDependencyInjection();
    var extension = base.CreateContainerExtension() as DryIocContainerExtension;
    return new DryIocContainerExtension(extension.Instance.WithDependencyInjectionAdapter(services));
}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<Views.DataGridDemo>();

    containerRegistry.RegisterDialog<Views.Common.InfoDialog>();
    containerRegistry.RegisterDialog<Views.Common.ErrorDialog>();
    containerRegistry.RegisterDialog<Views.Common.PrismDialog>();
}

/// <summary>
/// 使用微软官方依赖注入
/// </summary>
/// <returns></returns>
private IServiceCollection MicrosoftDependencyInjection()
{
    return new ServiceCollection()
        .AddHttpClient()
        .AddLogging(loggingBuilder =>
        {
            // TODO
        });
}
xmlns:prism="http://prismlibrary.com/"  
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:cvt="clr-namespace:Module.Project1.Common.Converter" 

<UserControl.Resources>
    <cvt:TypeConv x:Key="TypeConverter"/>
</UserControl.Resources>

<ContentControl prism:RegionManager.RegionName="{x:Static base:RegionNames.MainRegion}"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>      

导航

using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System.Threading.Tasks;

public class DemoViewModel : BindableBase, INavigationAware
{
#region Field
    private readonly IDependencyService _dependencyService;

#endregion
#region Property

#endregion
#region Command

#endregion
#region Execute

#endregion
#region Method

#endregion
public DemoViewModel(IDependencyService dependencyService)
{
    _dependencyService = dependencyService;
}
#region INavigationAware
    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        // 导航进来时调用
        var guid = navigationContext.Parameters.GetValue<string>("Guid");
        var temp = navigationContext.Parameters.GetValue<string>("Parameter2");

        _dependencyService.TryApiMethod(() => GetInfoAsync());
    }
    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
        // 导航离开当前页,跳转到其他页时调用
    }
#endregion
}

其中,DependencyService是一般常用依赖注入项的集合,便于统一调用。

View事件 ViewModel响应

UserControl

using Microsoft.Xaml.Behaviors.Wpf;

<b:Interaction.Triggers>
        <b:EventTrigger EventName="Loaded">
            <b:InvokeCommandAction Command="{Binding LoadedCommand}"/>
        </b:EventTrigger>
</b:Interaction.Triggers>


/// <summary>
/// 当前属性集合实体对象
/// </summary>
public DtoEntity PropSetEntity { get; set; }

public DelegateCommand LoadedCommand => new DelegateCommand(ExecuteLoadedCommand); // cmd
void ExecuteLoadedCommand()
{
_dependencyService.RegionManager.RequestNavigate(RegionNames.MainRegion, nameof(Views.DataGridDemo));
}
private readonly DependencyService _dependencyService;
public MainWindowViewModel(DependencyService dependencyService)
{
_dependencyService = dependencyService;
}

ChildDialog

// father view
<DataGridTemplateColumn Header="内容" >
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button Content="详情" Foreground="Blue"
                        Command="{Binding DataContext.DetailInfoCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=DataGrid}}" 
                        CommandParameter="{Binding ElementName=ucChildDlg}"/>
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<base:DialogForm x:Name="ucChildDlg"/>

// father viewmodel
using Prism.Services.Dialogs;

public DelegateCommand<object> GetDataCommand { get; private set; }
DetailInfoCommand = new DelegateCommand<object>(DetailInfo_Click);

private void DetailInfo_Click(object obj)
{
    if (obj is DialogForm childDlg && PropSetEntity.SelectedItem is DemoDto dto)
    {
        var parameters = new DialogParameters
        {
            { "dto", dto}
        };
        childDlg.Show(new DemoDetailInfo(), parameters, () => { });
        childDlg.FormMargin = new Thickness(20, 20, 20, 20);
    }
}

// child viewmodel
public class DemoDetailInfoViewModel : BindableBase, IDemoDialogAware
{
    public void OnDialogOpened(IDialogParameters parameters)
    {
        var dto = parameters.GetValue<DemoDto>("dto");
    }
}

DataGrid

<DataGrid Grid.Row="0" x:Name="DataGrid1" ItemsSource="{Binding ItemsSourceData}" SelectedItem="{Binding SelectedItem}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="SelectionChanged">
            <b:InvokeCommandAction Command="{Binding SelectionChangedCommand}"
                                   CommandParameter="{Binding SelectedItem, ElementName=DataGrid1}"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="BeginningEdit">
            <b:InvokeCommandAction Command="{Binding DataGridBeginningEditCommand}"
                       PassEventArgsToCommand="True"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="CellEditEnding">
            <b:InvokeCommandAction Command="{Binding DataGridCellEditEndingCommand}"
                       PassEventArgsToCommand="True"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
    <DataGrid.Columns>
        <DataGridTextColumn Width="*" Header="列头提示2" Binding="{Binding PropertyName1}" IsReadOnly="True"/>
        <DataGridComboBoxColumn Width="*" Header="列头提示1" SelectedValueBinding="{Binding PropertyName2}"
                                           SelectedValuePath="Key" DisplayMemberPath="Value">
            <DataGridComboBoxColumn.ElementStyle>
                <Style TargetType="ComboBox">
                    <Setter Property="ItemsSource" Value="{Binding DataContext.PropertyName2Source, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
                    <Setter Property="SelectedValue" Value="{Binding Key, Converter={StaticResource propertyName2Converter}}"/>
                </Style>
            </DataGridComboBoxColumn.ElementStyle>
            <DataGridComboBoxColumn.EditingElementStyle>
                <Style TargetType="ComboBox">
                    <Setter Property="ItemsSource" Value="{Binding DataContext.PropertyName2Source, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
                    <Setter Property="SelectedValue" Value="{Binding Value}"/>
                </Style>
            </DataGridComboBoxColumn.EditingElementStyle>
        </DataGridComboBoxColumn>
        <DataGridTemplateColumn Header="操作" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                 <DataTemplate>
                     <Button Content="DetailInfo" Command="{Binding DataContext.DetailInfoCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=DataGrid}}" CommandParameter="{Binding ElementName=ucChildDlg}"/>
                 </DataTemplate>
             </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
<base:DialogForm x:Name="ucChildDlg"/>

PUBLIC ObservableCollection<DataGridRowDto> ItemsSourceData { get; private set; }
private object _selectedItem;
public object SelectedItem
{
get { return _selectedItem; }
set { SetProperty(ref _selectedItem, value); }
}
ItemsSourceData通过Clear、AddRange等操作更新UI数据;
注意:绑定的是公共属性;

using System.Windows.Controls;

public DelegateCommand<object> SelectionChangedCommand { get; private set; }
public DelegateCommand<object> DataGridBeginningEditCommand { get; private set; }
public DelegateCommand<object> DataGridCellEditEndingCommand { get; private set; }
public DelegateCommand<object> DetailInfoCommand { get; private set; }

SelectionChangedCommand = new DelegateCommand<object>(DataGrid_SelectionChanged);
DataGridBeginningEditCommand = new DelegateCommand<object>(DataGrid_BeginningEdit);
DataGridCellEditEndingCommand = new DelegateCommand<object>(DataGridCell_EditEnding);
DetailInfoCommand = new DelegateCommand<object>(DetailInfo_Click);

private void DetailInfo_Click(object obj)
{
    if (obj is DialogForm childDlg && SelectedItem is DataGridRowDto dto)
    {
        var parameters = new DialogParameters();
        parameters.Add("dto", dto);
        childDlg.Show(new ChildView(), parameters, () => { });
        childDlg.FormMargin = new System.Windows.Thickness(200, 100, 200, 100);
    }
}

private void DataGrid_SelectionChanged(object parameter)
{
  if(parameter != null){}
}


private string _preValue = string.Empty;
private void DataGrid_BeginningEdit(object parameter)
{
    if (parameter is DataGridBeginningEditEventArgs e)
    {
        if (e.Column.Header.Equals("列头提示1"))
        {
            _preValue = (e.Column.GetCellContent(e.Row) as ComboBox).SelectedValue.ToString();
        }
    }
}

private void DataGridCell_EditEnding(object parameter)
{
    if (parameter is DataGridCellEditEndingEventArgs e)
    {
        string newValue = string.Empty;
        if (e.Column.Header.Equals("列头提示1"))
        {
            newValue = (e.EditingElement as ComboBox).SelectedValue.ToString();
            if (_preValue != newValue
                && int.TryParse(newValue, out int type)
                && e.Row.DataContext is ExampleEto item)
            {
                // TODO
            }
        }
    }
}

其中,CommandParameter的优先级高于PassEventArgsToCommand,若两者同时出现,传递的参数是CommandParameter的值。

ComboBox

<ComboBox x:Name="ComboBox1" SelectedValuePath="Key" DisplayMemberPath="Value"
          ItemsSource="{Binding DtoSource}" SelectedItem="{Binding SelectedDto}"
          SelectedValue="{Binding DtoSelectedValue}" SelectedIndex="{Binding DtoIndex}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="SelectionChanged">
            <b:InvokeCommandAction Command="{Binding ComboBoxDtoSelectionChangedCommand}" PassEventArgsToCommand="True" />
        </b:EventTrigger>
    </b:Interaction.Triggers>
</ComboBox>

using Prism.Mvvm;
private string _dtoSelectedValue;
public string DtoSelectedValue
{
get => _dtoSelectedValue;
set => SetProperty(ref _dtoSelectedValue, value);
}

public DelegateCommand ComboBoxDtoSelectionChangedCommand { get; private set; }
ComboBoxDtoSelectionChangedCommand = new DelegateCommand<object>(ComboBoxDto_SelectionChanged);

private void ComboBoxDto_SelectionChanged(object parameter)
{
   if (parameter is SelectionChangedEventArgs e && e.OriginalSource is ComboBox cmb) { }
}

CheckBox

<CheckBox x:Name="CheckBox1" Tag="{x:Static comm:ParaControlType.XXX}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="Checked">
            <b:InvokeCommandAction Command="{Binding CheckBoxItemCheckedCommand}" PassEventArgsToCommand="True"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="Unchecked">
            <b:InvokeCommandAction Command="{Binding CheckBoxItemUncheckedCommand}" CommandParameter="{Binding ElementName=CheckBox1}"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</CheckBox>

<CheckBox  x:Name="chk_XXX" IsChecked="{Binding XXX, Converter={StaticResource StringToBoolConverter}}" Tag="XXX"
           IsEnabled="{Binding EditingItem.XXXIsEnable}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="Checked">
            <b:InvokeCommandAction Command="{Binding CheckBoxValueCheckedCommand}" PassEventArgsToCommand="True"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="Unchecked">
            <b:InvokeCommandAction Command="{Binding CheckBoxValueUncheckedCommand}" PassEventArgsToCommand="True"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</CheckBox>
public DelegateCommand<object> CheckBoxValueCheckedCommand { get; private set; }
CheckBoxValueCheckedCommand = new DelegateCommand<object>(CheckBoxValue_Checked);
private void CheckBoxValue_Checked(object parameter)
{
    if (parameter is RoutedEventArgs e && e.OriginalSource is CheckBox ckb) { }
}

ListBox + CheckBox

<ListBox Grid.Row="5" x:Name="ListBox1" Margin="2" ItemsSource="{Binding ListBox1Source}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding PropertyName}" IsChecked="{Binding IsCheck}" x:Name="CheckBox2" Tag="{Binding}">
                <b:Interaction.Triggers>
                    <b:EventTrigger EventName="Checked">
                        <b:InvokeCommandAction Command="{Binding DataContext.ListBox1CheckedCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" 
                                               PassEventArgsToCommand="True"/>
                    </b:EventTrigger>
                    <b:EventTrigger EventName="Unchecked">
                        <b:InvokeCommandAction Command="{Binding DataContext.ListBox1UncheckedCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" 
                                               CommandParameter="{Binding ElementName=CheckBox2, Path=Tag}"/>
                    </b:EventTrigger>
                </b:Interaction.Triggers>
            </CheckBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

TextBox

<TextBox x:Name="TextBox1" Text="{Binding EditingItem.XXX}" Tag="XXX" IsEnabled="{Binding EditingItem.XXXIsEnable}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="TextChanged">
            <b:InvokeCommandAction Command="{Binding TextBox1TextChangedCommand}"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="KeyDown">
            <b:InvokeCommandAction Command="{Binding TextBox1KeyDownCommand}" PassEventArgsToCommand="True"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</TextBox>
private void TextBox1_KeyDown(object parameter)
{
    if (parameter is KeyEventArgs e && e.Key == System.Windows.Input.Key.Enter && e.OriginalSource is TextBox txt)
    {
        // TODO
    }
}

RadioCheck

可参考WPF 属性值绑定、转换

Button

<Button Content="测试" x:Name="ButtonTest" Command="{Binding ButtonTestCommand}" CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}" />

DelegateCommand<Button> ButtonQueryCommand;
ButtonQueryCommand = new DelegateCommand<Button>(Test_Click);

Grid 鼠标响应

<Grid Background="Transparent">
    <Grid.InputBindings>
        <MouseBinding MouseAction="LeftClick" 
                      Command="{Binding DataContext.NavigatePatrolCarCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
                      CommandParameter="{Binding Guid}"/>
    </Grid.InputBindings>
</Grid>

TreeView

<TreeView Name="TreeView1" ItemTemplate="{DynamicResource ItemNode}"
          ScrollViewer.HorizontalScrollBarVisibility="Auto"
          VirtualizingPanel.IsVirtualizing="True"
          VirtualizingStackPanel.VirtualizationMode ="Standard">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="SelectedItemChanged">
            <b:InvokeCommandAction Command="{Binding TreeView1SelectedItemChangedCommand}"
                                   CommandParameter="{Binding RelativeSource={x:Static RelativeSource.Self}}"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</TreeView>

TabControl

<TabControl prism:RegionManager.RegionName="{x:Static local:RegionNames.AdvancedSetup}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Visibility" Value="{Binding DataContext.IsAvailable, Converter={coverters:BooleanToVisibilityConverter}}"/>
            <Setter Property="Header" Value="{Binding DataContext.Name}"/>
        </Style>
    </TabControl.ItemContainerStyle>
</TabControl>

regionManager.RegisterViewWithRegion(RegionNames.AdvancedSetup, tabView1);
regionManager.RegisterViewWithRegion(RegionNames.AdvancedSetup, tabView2);

tabView1ViewModel中需要包含属性Name、IsAvailable等信息。

PagerSimple

xmlns:ws="https://wessoncontrol.com/WessonControl"

<ws:PagerSimple HorizontalAlignment="Center" PageSize="{Binding SelectedItem.PagerSize, Mode=TwoWay}"
                  CurrentPageCount="{Binding SelectedItem.CurrentPageCount, Mode=TwoWay}"
                  IsPagerInitialized="{Binding SelectedItem.IsPagerInitialized, Mode=TwoWay}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="PageChangedEvent">
            <b:InvokeCommandAction Command="{Binding GetDataCommand}" PassEventArgsToCommand="True"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>
</ws:PagerSimple>
// 1
public DelegateCommand<object> GetDataCommand { get; private set; }
// 2
GetDataCommand = new DelegateCommand<object>(GetData_Click);
// 3
private void GetData_Click(object parameter)
{
    if (parameter is PagerSimpleEventArgs e)
    {
        LocalParking.TryApiMethod(() => DataBindAsync(e.PageIndex, e.PageSize));
    }
}

RaiseCanExecuteChanged

using System.Reflection;
private void RaiseCanExecuteChangedAll()
{
    var props = new List<PropertyInfo>(this.GetType().GetProperties());
    foreach (PropertyInfo prop in props)
    {
        if (prop.PropertyType.IsSubclassOf(typeof(DelegateCommandBase)))
        {
            var cmd = (DelegateCommandBase)prop.GetValue(this, null);
            cmd.RaiseCanExecuteChanged();
        }
    }
}

ViewModel找到View控件

var region = _regionManager.Regions[RegionNames.RegionName1];
if (region != null && region.Views.FirstOrDefault() is Views.View1 view)
{
    _dataGrid1 = view.DataGrid1;     
}

Prism + DialogInfo

public IDialogService DialogService { get; }

public static void PrismShowInfo(string message)
{
    var cts = new CancellationTokenSource(5000);
    cts.Token.Register(() =>
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            EventAggregator.GetEvent<LoadingFinishedEvent>().Publish();
        });
    });
    Task.Run(() =>
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            var parameters = new DialogParameters($"title=提示:&message={message}&canOperate=Collapsed")
            {
                { "cts", cts }
            };
            DialogService.ShowDialog("MessageDialog", parameters, null);
        });
    }, cts.Token);
}

public static void PrismShowConfirm(string message, Action<IDialogResult> callback = null)
{
    var cts = new CancellationTokenSource(5000);
    cts.Token.Register(() =>
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            EventAggregator.GetEvent<LoadingFinishedEvent>().Publish();
        });
    });
    Task.Run(() =>
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            var parameters = new DialogParameters($"title=提示:&message={message}&canOperate=Visible")
            {
                { "cts", cts }
            };
            DialogService.ShowDialog("MessageDialog", parameters, callback);
        });
    }, cts.Token);
}

Prism + DialogForm蒙版形式

xaml

<UserControl x:Class="WessonControll.Views.PrismDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"           
             prism:ViewModelLocator.AutoWireViewModel="True">
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterOwner" />
            <Setter Property="ShowInTaskbar" Value="False" />
            <Setter Property="SizeToContent" Value="WidthAndHeight" />
            <Setter Property="WindowStyle" Value="None" />
            <Setter Property="AllowsTransparency" Value="True" />
            <Setter Property="Background" Value="Transparent" />
        </Style>
    </prism:Dialog.WindowStyle>

    <Grid>
        <Border
            Width="{Binding DialogWidth}"
            Height="{Binding DialogHeight}"
            Background="{StaticResource RegionBrush}"
            BorderBrush="{StaticResource PanelBorderBrush}"
            BorderThickness="1"
            CornerRadius="4">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid Margin="24,20,24,0">
                    <TextBlock
                        FontSize="16"
                        Foreground="{DynamicResource DefaultForegroundBrush}"
                        Text="{Binding Title}" />
                    <Button
                        Width="12"
                        Height="12"
                        Margin="4"
                        HorizontalAlignment="Right"
                        BorderThickness="0"
                        Command="{Binding CloseCommand}"
                        Style="{StaticResource ButtonDefault}">
                        <Button.Background>
                            <ImageBrush ImageSource="{DynamicResource MessageDialogSource}" />
                        </Button.Background>
                    </Button>
                </Grid>
                <ContentControl Grid.Row="1" x:Name="contentControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
            </Grid>
        </Border>
    </Grid>
</UserControl>

cs

using Prism.Regions;
using System.Windows;
using System.Windows.Controls;
using WessonControll.ViewModels;

namespace WessonControll.Views
{
    /// <summary>
    /// Interaction logic for PrismDialog
    /// </summary>
    public partial class PrismDialog : UserControl
    {
        public PrismDialog(IRegionManager regionManager)
        {
            InitializeComponent();
            var regionName = System.Guid.NewGuid().ToString();
            if (regionManager != null && !regionManager.Regions.ContainsRegionWithName(regionName))
            {
                SetRegionManager(regionManager, contentControl, regionName);
            }
            if (this.DataContext is PrismDialogViewModel vm)
            {
                vm.RegionName = regionName;
            }
        }
        private void SetRegionManager(IRegionManager regionManager, DependencyObject regionTarget, string regionName)
        {
            RegionManager.SetRegionName(regionTarget, regionName);
            RegionManager.SetRegionManager(regionTarget, regionManager);
        }
    }
}

viewmodel

using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Linq;

namespace WessonControll.ViewModels
{
        public class PrismDialogViewModel : BindableBase, IDialogAware
	{
	    #region Fields
	    private readonly DependencyService _dependencyService;
	    private readonly IContainerExtension _container;
	    /// <summary>
	    /// 可否关闭弹框,默认true可以关闭
	    /// </summary>
	    private bool _bCanClosed;
	    private readonly string _message;
	    #endregion

	    #region Properties
	    public string RegionName { get; set; }
	    private string _tittle = "页面标题";
	    public string Title
	    {
	        get => _tittle;
	        set => SetProperty(ref _tittle, value);
	    }
	    private double _dialogWidth;
	    public double DialogWidth
	    {
	        get => _dialogWidth;
	        set => SetProperty(ref _dialogWidth, value);
	    }
	    private double _dialogHeight;
	    public double DialogHeight
	    {
	        get => _dialogHeight;
	        set => SetProperty(ref _dialogHeight, value);
	    }
	    private bool _closeVisible;
	    /// <summary>
	    /// 关闭按钮的可见性
	    /// </summary>
	    public bool CloseVisible
	    {
	        get => _closeVisible;
	        set => SetProperty(ref _closeVisible, value);
	    }

	    #endregion

	    #region Commands
	    public DelegateCommand CloseCommand => new DelegateCommand(ExecuteCloseCommand);

	    #endregion

	    public PrismDialogViewModel(DependencyService dependencyService, IContainerExtension container)
	    {
	        _dependencyService = dependencyService;
	        _container = container;
	        dependencyService.EventAggregator.GetEvent<DialogCanCloseEvent>().Subscribe(DialogCanClose_Event);
	        dependencyService.EventAggregator.GetEvent<DialogCloseEvent>().Subscribe(DialogClose_Event);
	        DialogWidth = 1000;
	        DialogHeight = 820;
	        _bCanClosed = true;
	        _message = "有新的操作未保存,是否关闭?";
	    }

	    #region Execute
	    private void DialogCanClose_Event(bool bClose)
	    {
	        _bCanClosed = bClose;
	    }
	    private void DialogClose_Event(DialogParameters obj)
	    {
	        DialogResult result = new DialogResult(ButtonResult.Ignore, obj);
	        Close(result);
	    }

	    private void ExecuteCloseCommand()
	    {
	        Close(new DialogResult(ButtonResult.Ignore));
	    }
	    private void Close(DialogResult result)
	    {
	        if (_bCanClosed)
	        {
	            _dependencyService.RegionManager.Regions.Remove(RegionName);
	            RequestClose?.Invoke(result);
	        }
	        else
	        {
	            _dependencyService.DialogService.ShowMessage("提示:", _message, System.Windows.Visibility.Visible, callback =>
	            {
	                if (callback.Result != ButtonResult.OK)
	                {
	                    return;
	                }
	                _dependencyService.RegionManager.Regions.Remove(RegionName);
	                RequestClose?.Invoke(result);
	            });
	        }
	    }

	    #endregion
	    #region Interface IDialogAware

	    public event Action<IDialogResult> RequestClose;
	    public bool CanCloseDialog()
	    {
	        return true;
	    }

	    public void OnDialogClosed()
	    {
	        _dependencyService.EventAggregator.GetEvent<DialogCanCloseEvent>().Unsubscribe(DialogCanClose_Event);
	        _dependencyService.EventAggregator.GetEvent<DialogCloseEvent>().Unsubscribe(DialogClose_Event);
	    }

	    public void OnDialogOpened(IDialogParameters parameters)
	    {
	        Title = parameters.GetValue<string>("title");
	        DialogWidth = parameters.GetValue<double>("width");
	        DialogHeight = parameters.GetValue<double>("height");
	        CloseVisible = parameters.GetValue<bool>("close");
	        var type = parameters.GetValue<Type>("type");
	        var source = type.FullName;

	        var region = _dependencyService.RegionManager.Regions[RegionName];
	        var view = region.Views.FirstOrDefault(x => x.GetType() == type);
	        if (view == null)
	        {
	            view = _container.Resolve(type, source);
	            region.Add(view);
	        }
	        region.Activate(view);

	        var para = parameters.GetValue<NavigationParameters>("navigationParameters");
	        _dependencyService.RegionManager.RequestNavigate(RegionName, source, para);
	    }
	    #endregion
	}
}

注意事项

ViewModel可使用事件控制View界面元素

比如TreeView控件置顶,ViewModel定义委托事件,View中操作控件;

// ViewModel
public event EventHandler ScrollToTopEvent;
ScrollToTopEvent?.Invoke(this, EventArgs.Empty);

public XXView()
{
    InitializeComponent();
    if (this.DataContext is XXViewModel vm)
    {
        vm.ScrollToTopEvent += Vm_ScrollToTopEvent;
    }
}
private void Vm_ScrollToTopEvent(object sender, System.EventArgs e)
{
    WSCommFunc.TreeViewScrollToTop(TreeView1);
}

ViewModel内最好不要与用户交互

比如选择文件,可以在View中实现,在ViewModel中同步;

// View
<Button Content="选择" x:Name="ButtonSelectFile" Command="{Binding SelectFileCommand}" Click="ButtonSelectFile_Click" />
private void ButtonSelectFile_Click(object sender, System.Windows.RoutedEventArgs e)
{
    // System.Windows.Forms.OpenFileDialog openfile 选择文件
    var btn = (Button)sender;
    btn.CommandParameter = new FileInfo(openfile.FileName);
}
// ViewModel
private void SelectFile_Click(object parameter)
{
    if (parameter is FileInfo fi)
    {
        var fileName = fi.Name;
        var filePath = fi.FullName;
    }
}
posted @ 2021-06-11 11:33  wesson2019  阅读(789)  评论(3编辑  收藏  举报