WPF中, 如何将控件的触发事件绑定到ViewModel

在DataGrid 等控件中, 有很多这种带闪电符号的触发事件. 如果用传统的事件驱动, 则直接在后台中建立 一个private PropertyChanged(Sender s, EventAgars Args) 即可. 但是如果需要绑定到ViewModel的话? 应该怎么做?
WPF中, 如何将控件的触发事件绑定到ViewModel_第1张图片
带闪电符号的触发事件

实现viewModel绑定前端触发事件的写法:

        <DataGrid
            x:Name="myDataGrid"
            AlternationCount="2"
            AutoGenerateColumns="False"
            FontSize="24"
            ItemsSource="{Binding Students}"
            SelectedItem="{Binding SelectStudent}"
            SelectionMode="Extended">

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding DataGridSelectedCommand}" CommandParameter="{Binding ElementName=myDataGrid, Path=SelectedItems}" />
                i:EventTrigger>
            i:Interaction.Triggers>
            <DataGrid.ColumnHeaderStyle>
                <Style TargetType="DataGridColumnHeader">
                    "BorderThickness" Value="0,0,0,3" />
                    "Cursor" Value="Hand" />
                    "FontWeight" Value="SemiBold" />
                    "HorizontalContentAlignment" Value="Center" />
                    "Margin" Value="0" />
                    "MinHeight" Value="25" />
                    "MinWidth" Value="0" />
                    "Background" Value="#2B2C31" />
                    "SnapsToDevicePixels" Value="True" />
                Style>
            DataGrid.ColumnHeaderStyle>
            <DataGrid.CellStyle>
                <Style TargetType="DataGridCell">
                    "HorizontalContentAlignment" Value="Center" />
                    "VerticalContentAlignment" Value="Center" />
                    "Template">
                        
                            "DataGridCell">
                                "{TemplateBinding Background}">
                                    "Center" VerticalAlignment="Center" />
                                
                            
                        
                    
                Style>
            DataGrid.CellStyle>
            <DataGrid.Columns>
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Id}"
                    Header="Id" />
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Age}"
                    Header="年龄" />
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Name}"
                    Header="姓名" />
                <DataGridTemplateColumn Header="操作">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock
                                    Margin="5"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Center"
                                    Background="White"
                                    FontFamily="{StaticResource fontAwesome}"
                                    FontSize="24"
                                    Tag="修改"
                                    Text="">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="MouseUp">
                                            <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.DataGridUpDateCommand}" CommandParameter="{Binding}" />
                                        i:EventTrigger>
                                    i:Interaction.Triggers>
                                    <TextBlock.Style>
                                        <Style TargetType="TextBlock">
                                            
                                                "IsMouseOver" Value="True">
                                                    "Cursor" Value="Hand" />
                                                    "Foreground" Value="Orange" />
                                                
                                                "IsMouseOver" Value="False">
                                                    "Foreground" Value="Black" />
                                                
                                            
                                        Style>
                                    TextBlock.Style>
                                TextBlock>
                                <TextBlock
                                    Margin="5"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Center"
                                    Background="White"
                                    FontFamily="{StaticResource fontAwesome}"
                                    Tag="删除"
                                    Text="">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="MouseUp">
                                            <i:InvokeCommandAction Command="{Binding DataContext.DataGridDeleteCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}" />
                                        i:EventTrigger>
                                    i:Interaction.Triggers>
                                    <TextBlock.Style>
                                        <Style TargetType="TextBlock">
                                            
                                                "IsMouseOver" Value="True">
                                                    "Cursor" Value="Hand" />
                                                    "Foreground" Value="Red" />
                                                
                                                "IsMouseOver" Value="False">
                                                    "Foreground" Value="Black" />
                                                
                                            
                                        Style>
                                    TextBlock.Style>
                                TextBlock>
                            StackPanel>
                        DataTemplate>
                    DataGridTemplateColumn.CellTemplate>

                DataGridTemplateColumn>
            DataGrid.Columns>
        DataGrid>

分析核心代码:

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding DataGridSelectedCommand}" CommandParameter="{Binding ElementName=myDataGrid, Path=SelectedItems}" />
                i:EventTrigger>
            i:Interaction.Triggers>

i的命名空间 : xmlns:i=“http://schemas.microsoft.com/xaml/behaviors”

使用触发器, 事件触发器, 将前端的触发事件写在EventName中 SelectionChanged. 然后把事件绑定到后台, 将多选的Student 以CommandParameter的形式传入后端

后端代码:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MathNet.Numerics.Distributions;
using NavTest.Eneities;
using SqlSugar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NavTest.ViewModels
{
    public partial class Page3ViewModel:ObservableObject
    {
        [ObservableProperty]
        private ObservableCollection<Student> students = new();

        public Page3ViewModel()
        {
            for (int i = 0; i < 15; i++)
            {
                Students.Add(
                    new()
                    {
                        Id = i + 1,
                        Name = $"StudentName{i}",
                        Age = $"{i}+10",
                        Description = $"str+{i}"
                    }
                );
            }
        }

        [RelayCommand]
        public void DataGridDelete(Student student)
        {

        }

        //[RelayCommand]

        //public void DataGridUpDate(Student student)
        //{

        //}

        public RelayCommand<Student> DataGridUpDateCommand => new RelayCommand<Student>((arg) =>
        {

        });

        [RelayCommand]
        public void DataGridSelected(IList<object> objs)
        {
            MyStudents = new();
            foreach (var item in objs)
            {
                if (item is Student stu)
                {
                    MyStudents.Add(stu);
                }
            }

            Student stu1 = SelectStudent;
        }

        [RelayCommand]
        public void ItemControlCmd(Student student)
        {

        }

        [ObservableProperty]
        private ObservableCollection<Student> myStudents = new ();
        [ObservableProperty]
        private Student selectStudent = new();
    }
}

完整的前端代码:

<UserControl
    x:Class="NavTest.Views.Page3"
    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:hc="https://handyorg.github.io/handycontrol"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:NavTest.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:mv="clr-namespace:NavTest.ViewModels"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:tt="clr-namespace:NavTest.Eneities"
    xmlns:vc="clr-namespace:NavTest.Components"
    d:DataContext="{d:DesignInstance mv:Page3ViewModel}"
    d:DesignHeight="450"
    d:DesignWidth="800"
    FontSize="24"
    mc:Ignorable="d">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        Grid.RowDefinitions>
        <DataGrid
            x:Name="myDataGrid"
            AlternationCount="2"
            AutoGenerateColumns="False"
            FontSize="24"
            ItemsSource="{Binding Students}"
            SelectedItem="{Binding SelectStudent}"
            SelectionMode="Extended">

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding DataGridSelectedCommand}" CommandParameter="{Binding ElementName=myDataGrid, Path=SelectedItems}" />
                i:EventTrigger>
            i:Interaction.Triggers>
            <DataGrid.ColumnHeaderStyle>
                <Style TargetType="DataGridColumnHeader">
                    "BorderThickness" Value="0,0,0,3" />
                    "Cursor" Value="Hand" />
                    "FontWeight" Value="SemiBold" />
                    "HorizontalContentAlignment" Value="Center" />
                    "Margin" Value="0" />
                    "MinHeight" Value="25" />
                    "MinWidth" Value="0" />
                    "Background" Value="#2B2C31" />
                    "SnapsToDevicePixels" Value="True" />
                Style>
            DataGrid.ColumnHeaderStyle>
            <DataGrid.CellStyle>
                <Style TargetType="DataGridCell">
                    "HorizontalContentAlignment" Value="Center" />
                    "VerticalContentAlignment" Value="Center" />
                    "Template">
                        
                            "DataGridCell">
                                "{TemplateBinding Background}">
                                    "Center" VerticalAlignment="Center" />
                                
                            
                        
                    
                Style>
            DataGrid.CellStyle>
            <DataGrid.Columns>
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Id}"
                    Header="Id" />
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Age}"
                    Header="年龄" />
                <DataGridTextColumn
                    Width="*"
                    Binding="{Binding Name}"
                    Header="姓名" />
                <DataGridTemplateColumn Header="操作">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock
                                    Margin="5"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Center"
                                    Background="White"
                                    FontFamily="{StaticResource fontAwesome}"
                                    FontSize="24"
                                    Tag="修改"
                                    Text="">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="MouseUp">
                                            <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.DataGridUpDateCommand}" CommandParameter="{Binding}" />
                                        i:EventTrigger>
                                    i:Interaction.Triggers>
                                    <TextBlock.Style>
                                        <Style TargetType="TextBlock">
                                            
                                                "IsMouseOver" Value="True">
                                                    "Cursor" Value="Hand" />
                                                    "Foreground" Value="Orange" />
                                                
                                                "IsMouseOver" Value="False">
                                                    "Foreground" Value="Black" />
                                                
                                            
                                        Style>
                                    TextBlock.Style>
                                TextBlock>
                                <TextBlock
                                    Margin="5"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Center"
                                    Background="White"
                                    FontFamily="{StaticResource fontAwesome}"
                                    Tag="删除"
                                    Text="">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="MouseUp">
                                            <i:InvokeCommandAction Command="{Binding DataContext.DataGridDeleteCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}" />
                                        i:EventTrigger>
                                    i:Interaction.Triggers>
                                    <TextBlock.Style>
                                        <Style TargetType="TextBlock">
                                            
                                                "IsMouseOver" Value="True">
                                                    "Cursor" Value="Hand" />
                                                    "Foreground" Value="Red" />
                                                
                                                "IsMouseOver" Value="False">
                                                    "Foreground" Value="Black" />
                                                
                                            
                                        Style>
                                    TextBlock.Style>
                                TextBlock>
                            StackPanel>
                        DataTemplate>
                    DataGridTemplateColumn.CellTemplate>

                DataGridTemplateColumn>
            DataGrid.Columns>
        DataGrid>

        <WrapPanel
            Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试1" />
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试2" />
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试3" />
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试4" />
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试5" />
            <TextBlock
                Margin="5,5,5,5"
                Foreground="White"
                Text="测试6" />
        WrapPanel>

        <Grid Grid.Row="1" Grid.Column="1">
            <ItemsControl AlternationCount="2" ItemsSource="{Binding MyStudents}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    ItemsPanelTemplate>
                ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Border x:Name="border" Padding="2">
                            <StackPanel>
                                <TextBlock Foreground="White" Text="{Binding Name}" />
                                <TextBlock Foreground="White" Text="{Binding Age}" />
                                <Button
                                    Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.ItemControlCmdCommand}"
                                    CommandParameter="{Binding}"
                                    Content="{Binding Description}"
                                    Foreground="White" />
                            StackPanel>
                        Border>
                        <DataTemplate.Triggers>
                            <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                                <Setter TargetName="border" Property="Background" Value="red" />
                            Trigger>
                        DataTemplate.Triggers>
                    DataTemplate>
                ItemsControl.ItemTemplate>
            ItemsControl>
        Grid>
    Grid>
UserControl>


如果在一个有ItemSource的控件内找不到 后台的Property 和command, 可以尝试 binding ElementName 和binding Relationsource

例如command 可以 binding Relationsource = {RelationSource AncestorType = window} path = datacontext. xxxcommand
commandparameter={binding} 返回单个class为数据源

CommandParameter=“{Binding ElementName=myDataGrid, Path=SelectedItems}” 绑定别的控件上的属性 或者 用child的方式

一些补充的内容:

除了BooleanToVisibilityConverter之外,WPF框架还提供了许多其他的内置转换器。以下是一些常用的系统现有转换器的示例:

BooleanToVisibilityConverter: 将bool值转换为Visibility枚举值。
InverseBooleanConverter: 反转bool值,将true转换为false,将false转换为true。
StringFormatConverter: 格式化字符串,可以将值与指定的格式字符串进行组合。
DateTimeConverter: 将DateTime对象转换为不同格式的字符串,或者将字符串转换为DateTime对象。
BrushConverter: 将字符串表示的颜色转换为Brush对象。
ValueConverterGroup: 将多个转换器组合成一个组,按照顺序依次进行转换。
EnumToStringConverter: 将枚举值转换为对应的字符串表示。
NumericUpDownConverter: 用于增加和减少数值类型的转换器。
CollectionViewSource: 用于在集合和视图之间进行转换和筛选。
这只是一些常见的示例,WPF框架提供了更多的内置转换器,可以满足各种转换需求。你可以根据具体的场景和需求选择合适的转换器来使用。

eventTrriger
DataTrigger

常用触发器:

CallMethodAction
ChangePropertyAction
InvokeCommandAction


CallMethodAction 和 InvokeCommandAction 是在 WPF 中用于触发操作的两种不同方式,它们有一些区别,并且在特定的情况下可能不可互相替代。

CallMethodAction:CallMethodAction 允许你直接调用指定的方法。你可以通过设置 TargetObject 属性指定要调用方法的对象,并使用 MethodName 属性指定要调用的方法名称。这种方式适用于简单的、特定于 UI 的操作,例如在按钮点击或其他事件发生时执行某个方法。它可以方便地将事件触发与方法调用关联起来,但缺点是它与 UI 逻辑紧耦合,并且无法利用 WPF 中的命令系统。

InvokeCommandAction:InvokeCommandAction 允许你通过绑定一个命令来执行操作。你可以使用 Command 属性绑定到一个实现了 ICommand 接口的命令对象。当触发与行为关联的事件时,命令的 Execute 方法将被调用,而命令的 CanExecute 方法决定是否可以执行。这种方式更符合 MVVM 架构和解耦原则,它将 UI 逻辑与业务逻辑分离,并提供了更好的可测试性和可重用性。

虽然 CallMethodAction 和 InvokeCommandAction 实现了类似的功能,但在大多数情况下,推荐使用 InvokeCommandAction 和命令模式来处理用户交互。它更符合 MVVM 设计模式的理念,并且提供了更好的灵活性和可扩展性。但在一些简单的场景下,CallMethodAction 也可以作为一种快速临时解决方案。

因此,根据具体的需求和架构设计,你可以选择使用 CallMethodAction 或 InvokeCommandAction 来触发操作。


在 WPF 中,CallMethodAction 是一种交互行为(Interaction Behavior),它允许你通过 XAML 触发调用特定方法。它是 System.Windows.Interactivity 命名空间下的一个类,需要通过添加对 System.Windows.Interactivity 程序集的引用才能使用。

CallMethodAction 可以用于任何具有无参数的方法。它与事件触发器(EventTrigger)一起使用,当特定事件发生时,将触发并调用绑定的方法。

以下是使用 CallMethodAction 的示例:

CallMethodAction :===============


<StackPanel>
    <Button Content="Click Me">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:CallMethodAction TargetObject="{Binding}" MethodName="HandleButtonClick" />
            i:EventTrigger>
        i:Interaction.Triggers>
    Button>
StackPanel>

关闭窗口,用到window的close方法:
                <Button
                    Background="Red"
                    Content=""
                    Style="{StaticResource ControlButtonStyle}"
                    ToolTip="Close">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <i:CallMethodAction MethodName="Close" TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}}" />
                        i:EventTrigger>
                    i:Interaction.Triggers>
                Button>



ChangePropertyAction=============
例如:TargetObject="{Binding} 返回了DataContext,就是ViewModel,它的PropertyName就是里面的属性IsMarker

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:ChangePropertyAction PropertyName="IsMarker" Value="True" TargetObject="{Binding}"/>
        i:EventTrigger>
        <i:EventTrigger EventName="Closing">
            <i:ChangePropertyAction PropertyName="IsMarker" Value="False" TargetObject="{Binding}"/>
        i:EventTrigger>
    i:Interaction.Triggers>

最小化,用到window的Minimized属性:

                <Button
                    Background="#22FFFFFF"
                    Content=""
                    Style="{StaticResource ControlButtonStyle}"
                    ToolTip="Minimize">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <i:ChangePropertyAction
                                PropertyName="WindowState"
                                TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
                                Value="Minimized" />
                        i:EventTrigger>
                    i:Interaction.Triggers>
                Button>



<Button Content="Change Background">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:ChangePropertyAction TargetObject="{Binding ElementName=MyBorder}"
                                    PropertyName="Background"
                                    Value="Red" />
        i:EventTrigger>
    i:Interaction.Triggers>
Button>
<Border x:Name="MyBorder" Width="100" Height="100" Background="Green" />



<Button Content="Change Background">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
                                    PropertyName="Background"
                                    Value="Red" />
        i:EventTrigger>
    i:Interaction.Triggers>
Button>

=============

                        <RadioButton
                            Width="200"
                            Height="50"
                            Content="连接PLC"
                            FontSize="18"
                            Foreground="White"
                            Style="{DynamicResource RadioButtonMenuStyle}"
                            Tag="">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Checked">
                                    <i:InvokeCommandAction Command="{Binding ConnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=RadioButton}}" />
                                i:EventTrigger>
                            i:Interaction.Triggers>
                        RadioButton>


============


在 <i:EventTrigger> 元素中,可以使用不同的 EventName 属性来指定常见事件的名称,以触发相应的动作或触发器。以下是一些常用的 EventName 值示例:

Loaded:当元素加载完成时触发。
Unloaded:当元素卸载时触发。
MouseEnter:当鼠标指针进入元素时触发。
MouseLeave:当鼠标指针离开元素时触发。
MouseDown:当鼠标按下按钮时触发。
MouseUp:当鼠标释放按钮时触发。
Click:当元素被点击时触发。
Checked:当复选框或单选按钮的选中状态改变时触发。
TextChanged:当文本框的文本内容改变时触发。
PreviewMouseMove:鼠标在元素上移动。
PreviewMouseUp:鼠标释放按钮。
MouseEnter:鼠标进入元素。
MouseLeave:鼠标离开元素。
PreviewMouseWheel:滚动鼠标滚轮。
键盘事件:

PreviewKeyDown:按下键盘上的键。
PreviewKeyUp:释放键盘上的键。
KeyDown:按下键盘上的键(冒泡事件)。
KeyUp:释放键盘上的键(冒泡事件)。


SelectionChanged:当下拉列表、列表框或其他选择控件的选择项发生改变时触发。
这只是一些常见的 EventName 值示例,实际上,可以根据具体的控件和需求,选择适合的事件名称。根据控件的类型和事件的定义,可以在相关文档或控件的事件文档中找到更多可用的 EventName 值。


<Button Content="Toggle Size" Width="100" Height="30">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:Interaction.Behaviors>
                <ei:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
                                         PropertyName="WindowState">
                    <ei:ChangePropertyAction.Value>
                        <System:WindowState>
                            <System:WindowState x:FactoryMethod="FromValue">
                                <System:WindowState.Normal />
                                <System:WindowState.Maximized />
                            System:WindowState>
                        System:WindowState>
                    ei:ChangePropertyAction.Value>
                ei:ChangePropertyAction>
            i:Interaction.Behaviors>
        i:EventTrigger>
    i:Interaction.Triggers>
Button>



========i:DataTrigger========

{Binding RelativeSource  = {RelativeSource Self} 
{Binding RelativeSource = {RelativeSource  AncestorType=Button}}  

{Binding ElementName=TestTBlock, Path=Name}


<Button Content="Click Me">
    <i:Interaction.Triggers>
        <i:DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path = IsMouseOver}" Value="False">
            <i:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource Self}}"
                                    PropertyName="BackGround"
                                    Value="Red" />
        i:DataTrigger>
    i:Interaction.Triggers>
Button>

你可能感兴趣的:(wpf)