WPF-如何处理从MainWindow中的UserControl引发的事件并更新ViewModel

WPF-如何处理从MainWindow中的UserControl引发的事件并更新ViewModel,wpf,Wpf,我试图在UserControl1中引发一个事件,但我不知道如何处理该事件以在主窗口中显示UserControl2 MainWindow.xaml <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

我试图在UserControl1中引发一个事件,但我不知道如何处理该事件以在主窗口中显示UserControl2

MainWindow.xaml

<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:ViewModel1 />
    </Window.DataContext>

    <Window.Resources>
        <DataTemplate x:Key="Template1" DataType="{x:Type local:ViewModel1}">
            <local:UserControl1 />
        </DataTemplate>
        <DataTemplate x:Key="Template2" DataType="{x:Type local:ViewModel1}">
            <local:UserControl2 />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl Content="{Binding }">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource Template1}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding UserControlId}" Value="2">
                            <Setter Property="ContentTemplate" Value="{StaticResource Template2}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </Grid>
</Window>
UserControl1.xaml

<UserControl x:Class="WpfApp1.UserControl1"
             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:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Label Content="User Control 1" />
        <Button x:Name="btnNext" Content="Next" Click="btnNext_Click"></Button>
    </Grid>
</UserControl>
UserControl2.xaml

<UserControl x:Class="WpfApp1.UserControl2"
             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:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Label Content="User Control 2" />
    </Grid>
</UserControl>
ViewModel1.cs

using System.ComponentModel;

namespace WpfApp1
{
    public class ViewModel1 : INotifyPropertyChanged
    {
        public int UserControlId { get; set; }

        public ViewModel1()
        {
            UserControlId = 2;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
using System.ComponentModel;

namespace WpfApp1
{
    public class ViewModel1 : INotifyPropertyChanged
    {
        private int _userControlId;

        public int UserControlId { 
            get { return _userControlId; }

            set 
            {
                _userControlId = value;
                RaisePropertyChanged("UserControlId");
            }
        }

        private void RaisePropertyChanged(string v = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v));
        }

        public ViewModel1()
        {
            UserControlId = 1;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
我想我必须更新ViewModel1中的UserControlId属性才能更改用户控件,但是在哪里处理以及如何让ViewModel1实例更改该属性

编辑1 很抱歉,ViewModel1构造函数中的输入错误,我的意思是将UserControlId属性初始化为1,而不是2

当我运行它时,我看到主窗口中加载了UserControl1的窗口。 UserControl1有一个按钮“下一步”。 单击UserControl1中的按钮,我想显示UserControl2。 所以我在button click事件处理程序中引发MyEvent routed事件。
现在,在哪里附加和编写MyEvent的事件处理程序,以及如何让ViewModel1实例更改其UserControlId属性?

这里不需要路由事件。将ViewModel分配给MainWindow,并在MainViewModel中添加属性“UserControlId”。然后,当您在主窗口的DataContext级别上对UserControlId的值编写触发器时,XAML代码将正常工作。

为此,您需要在两个视图模型之间进行调解。调解的一种方法是将主窗口作为调解器:它侦听来自子窗口的事件,然后将它们路由到所需的目的地。另一种方法是通过事件聚合器。大多数MVVM框架都有一个。据我所知,WPF世界中最好的开源软件是。在一个视图模型中订阅某种消息,然后从另一个视图模型发送事件,事件聚合器确保事件路由到其目标。有关更多详细信息,请参阅他们的文档。

我终于实现了这一点。在ViewModel1中使用属性名称更改了引发的事件,在主窗口中添加了事件侦听器

这是更改的文件

ViewModel1.cs

using System.ComponentModel;

namespace WpfApp1
{
    public class ViewModel1 : INotifyPropertyChanged
    {
        public int UserControlId { get; set; }

        public ViewModel1()
        {
            UserControlId = 2;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
using System.ComponentModel;

namespace WpfApp1
{
    public class ViewModel1 : INotifyPropertyChanged
    {
        private int _userControlId;

        public int UserControlId { 
            get { return _userControlId; }

            set 
            {
                _userControlId = value;
                RaisePropertyChanged("UserControlId");
            }
        }

        private void RaisePropertyChanged(string v = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(v));
        }

        public ViewModel1()
        {
            UserControlId = 1;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
MainWindow.cs

using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            AddHandler(UserControl1.MyEvent, new RoutedEventHandler(OnMyEvent));
        }

        private void OnMyEvent(object sender, RoutedEventArgs e)
        {
            var vm = (ViewModel1)DataContext;
            vm.UserControlId = "2";
        }
    }
}

“将ViewModel分配给MainWindow”-我已经这样做了。触发器将更改UserControl,但如何触发它?从您提供的代码中,我可以看到属性“UserControlId”位于“ViewModel1”中,这就是DataTrigger无法获得正确的属性绑定的原因。它应该在MainViewModel中,在单击“下一步”按钮时也将属性的值更改为“2”。您可以使用caliburn.micro来执行此操作,查看“它侦听孩子们的事件,然后将其发送到他们所需的目的地。”-您能给我指一下可以执行此操作的资源吗?是的,我添加了链接。非常感谢您@smk