Prism技巧

Prism 8.0

xmlns:prism="http://prismlibrary.com/"  
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.SyncDataRecordRegion}"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>      

View事件 ViewModel响应

UserControl

using Microsoft.Xaml.Behaviors.Wpf;
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"

<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 { get; private set; }
LoadedCommand = new DelegateCommand(UserControl_Loaded);

public DelegateCommand LoadedCommand => new DelegateCommand(UserControl_Loaded);

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">
                <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}"/>
                    </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);

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>

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 + Dialog

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);
}

注意事项

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;
    }
}
原文地址:https://www.cnblogs.com/wesson2019-blog/p/14874469.html