【问题标题】:Can't fire commands in window with frame无法在带框架的窗口中触发命令
【发布时间】:2016-10-26 21:25:57
【问题描述】:

我有一个 WPF 窗口,其网格包含 4 个矩形。其中之一有一个<frame> 用于显示页面,它在我的应用程序中使用。我想将命令添加到我的窗口以及页面上的这些按钮。

我使用的东西:MVVM,作为Mainwindow 的窗口和作为框架中的内容发布器的页面。

例如,我想使用按钮和命令登录整个应用程序。在我的框架中的页面上执行此操作时没有错误,但我不能在窗口中执行相同操作。

我想知道窗口是否失去焦点,因此在导航到框架中的页面时无法触发该事件。所以我尝试使用以下命令绑定来获取窗口:

<Button Content="&#xE143;" FontFamily="Segoe UI Symbol" 
  Command="{Binding CommandWhichDoesNotFire, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type vw:MainViewModel}}}" 
  Width="32">

在我的ViewModel“MainViewModel”中,我有一个公共的ICommand 属性,我在构造函数中对其进行了初始化:

    public ICommand CommandWhichDoesNotFire;
    public MainViewModel()
    {
        MessageBox.Show("VM is real");

        CommandWhichDoesNotFire= new TestCommand();
    }

我的 MainView 的 DataContextInitilizeComponents(); 之前的代码中设置 单击该按钮不会启动对我的命令的任何调用。它根本不开火。我想念什么?

【问题讨论】:

  • 您能否发布更多代码,具有最小的窗口以及如何设置 DataContext?没有它很难帮助你。
  • 您的 VS 控制台输出中是否报告了绑定错误?能不能运行Snoop看看绑定是否成功?

标签: c# wpf mvvm navigation command


【解决方案1】:

你应该有:

public ICommand CommandWhichDoesNotFire{get;set;}
public MainViewModel()
{
    MessageBox.Show("VM is real");

    CommandWhichDoesNotFire= new TestCommand(MyCommand);
}
private void MyCommand(object obj){
//Whatever you want to do
}

【讨论】:

    【解决方案2】:

    我想我已经找到了解决您问题的方法。
    Frame 出于某种原因不会继承其父级的 DataContext,即使您像这样明确设置 DataContext

    DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"  
    

    还是不行。它的作用是只设置框架的DataContext,而不是子元素:
    这是子元素的DataContext

    现在这让我想到,我们一直喜欢 WPF 及其控件的任何原因是能够从其父级继承 DataContextContextMenu 和现在的 Frame 除外。这是我第一次看到 oyur 问题时采用的方法:

    <Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>
    <Window.Resources>
        <!--<local:MainVM x:Key="mainVM"/>-->
        <local:LoginPage x:Key="login" />
        <!--DataContext="{StaticResource mainVM}"-->
        <ControlTemplate x:Key="ctrlTmpl">
            <local:LoginPage/>
        </ControlTemplate>
    
    </Window.Resources>
    <Grid>
        <!--<Button x:Name="button" Content="Do something" Click="btnDoSomething" HorizontalAlignment="Left" Margin="221,60,0,0" VerticalAlignment="Top" Width="75"/>-->
        <!--<Control Template="{StaticResource ctrlTmpl}"/> This works-->
        <Frame Content="{StaticResource login}" DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"  />
    </Grid>
    


    然后我想你可以用另一种方式做到这一点:

    <Window x:Class="WpfApplication1.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:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <!--<Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>-->
    <Window.Resources>
        <local:MainVM x:Key="mainVM"/>
        <local:LoginPage x:Key="login" DataContext="{StaticResource mainVM}"/>
        <!---->
        <ControlTemplate x:Key="ctrlTmpl">
            <local:LoginPage/>
        </ControlTemplate>
    
    </Window.Resources>
    <Grid>
        <!--<Button x:Name="button" Content="Do something" Click="btnDoSomething" HorizontalAlignment="Left" Margin="221,60,0,0" VerticalAlignment="Top" Width="75"/>-->
        <!--<Control Template="{StaticResource ctrlTmpl}"/> This works-->
        <Frame Content="{StaticResource login}"/>
    </Grid>
    


    请注意我如何将 VM 包含在资源中,然后将该实例用作控件DataContext。此时,当我单击我的 LoginPage.xaml 中的按钮时,顺便说一下 UserControl 它会触发位于我的 MainVM 中的命令。此时,您必须在后面的代码中分配Window DataContext,如下所示:

    public MainWindow()
        {
            InitializeComponent();
    
            var vm = this.TryFindResource("mainVM");
            if(vm != null)
            {
                this.DataContext = vm;
            }
        }  
    

    此时您可以使用某种触发器来浏览页面并使用不同的Pages 或UserControls。 HTH
    附言当我有机会时,我会从 MSDN 更新一些关于 Context Menu 和 Frame 的信息。快乐编码

    【讨论】:

      猜你喜欢
      • 2022-01-26
      • 1970-01-01
      • 2013-10-31
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-16
      相关资源
      最近更新 更多