我有一个 WPF 窗口,其网格包含 4 个矩形。其中之一有一个用于显示页面的
<frame>
,在我的应用程序中使用。我想向窗口和页面上的这些按钮添加命令。
我使用的东西:MVVM、Window 作为
Mainwindow
和 Pages 作为框架中的内容发布器。
例如,我想使用按钮和命令登录应用程序。在我的框架中的页面上执行此操作时没有错误,但我无法在窗口中执行相同的操作。
我想知道窗口是否失去焦点,因此在导航到框架中的页面时无法触发该事件。所以我尝试使用以下命令绑定来获取窗口:
<Button Content="" 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();
单击该按钮不会启动我的命令的任何调用。它根本不点火。伙计们,我错过了什么?
你应该有:
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
}
我想我已经找到了解决您问题的方法。由于某种原因,
Frame
不会继承其父级的DataContext
,即使您像这样显式设置DataContext
:
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"
还是不行。它的作用只是设置框架的
DataContext
而不是子元素:
这是子元素的
DataContext
:
现在这让我想到,我们一直喜欢 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
。