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

时间:2016-10-26 21:25:57

标签: c# wpf mvvm navigation command

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

我使用的东西:MVVM,Window as Mainwindow和Pages as contentpublisher in a frame。

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

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

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

在我的ViewModel&#34; MainViewModel&#34;我有一个公共ICommand属性,我在构造函数中初始化它:

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

        CommandWhichDoesNotFire= new TestCommand();
    }

我的MainView的DataContext设置在后面的代码之前InitilizeComponents(); 单击该按钮不会启动任何调用我的命令。它根本不会发射。我想念的是什么人?

2 个答案:

答案 0 :(得分: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
}

答案 1 :(得分: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,但ContextMenuFrame除外。这是我在看到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中的Command。此时,您必须在代码中分配Window DataContext,如下所示:

public MainWindow()
    {
        InitializeComponent();

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

现在,您可以使用某种触发器浏览网页并使用不同的PageUserControl。 HTH
附:当我有机会时,我将从MSDN更新有关上下文菜单和帧的一些信息。快乐编码