无法在带有框架的窗口中触发命令

问题描述 投票:0回答:2

我有一个 WPF 窗口,其网格包含 4 个矩形。其中之一有一个用于显示页面的

<frame>
,在我的应用程序中使用。我想向窗口和页面上的这些按钮添加命令。

我使用的东西:MVVM、Window 作为

Mainwindow
和 Pages 作为框架中的内容发布器。

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

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

<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 的

DataContext
是在后面的代码中设置的
InitilizeComponents();
单击该按钮不会启动我的命令的任何调用。它根本不点火。伙计们,我错过了什么?

c# wpf mvvm navigation command
2个回答
0
投票

你应该有:

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
}

0
投票

我想我已经找到了解决您问题的方法。由于某种原因,

Frame
不会继承其父级的
DataContext
,即使您像这样显式设置
DataContext

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

还是不行。它的作用只是设置框架的

DataContext
而不是子元素:

Frame's Data Context is set

这是子元素的

DataContext

Child element Data Context is NULL!

现在这让我想到,我们一直喜欢 WPF 及其控件的是从其父级继承

DataContext
的能力,除了
ContextMenu
和现在的
Frame
。这是我第一次看到你的问题时采取的方法:

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

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

<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>
</Window>

请注意我如何将虚拟机包含在资源中,然后使用该实例作为控件

DataContext
。此时,当我单击 LoginPage.xaml 中的按钮(顺便说一句,它是一个
UserControl
)时,它会触发位于 MainVM 中的命令。此时,您必须在后面的代码中分配
Window
DataContext
,如下所示:

public MainWindow()
    {
        InitializeComponent();

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

现在,您可以使用某种触发器来浏览页面并使用不同的

Page
UserControl

© www.soinside.com 2019 - 2024. All rights reserved.