如何将WPF页面中网格的数据上下文设置为其他WPF窗口

时间:2013-08-30 12:08:58

标签: wpf xaml datacontext

我是WPF的新手。我有一个WPF窗口,在同一个项目中我有一个WPF页面。该页面包含要加载到窗口中的键盘布局。窗口有一个框架,其源设置为页面。现在页面中的所有按钮都是WPF自定义控件。这些控件有两个依赖属性,如IsCapsOn和IsShiftOn。更改时这些依赖项属性会更改按钮上的文本(“a”变为“A”表示按下了大写字母)。      上面的依赖属性通过名称IsCapsPressed和IsShiftPressed绑定到主窗口的依赖属性。当用户在主窗口按下大写键时,后端的IsCapsPressed属性会发生变化,因此IsCapsOn也必须因绑定而改变。为此,我必须将页面中按钮的数据上下文设置为主窗口,因为在其中定义了依赖项属性。以下是代码snipets:

 //page
<Page x:Class="Philips.PmsUS.VirtualKeyboard.Resources.Layouts.USKeyboardPage"
      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:kb="clr-namespace:Philips.PmsUS.KeyboardButton;assembly=Philips.PmsUS.KeyboardButton"
      mc:Ignorable="d"
      x:Name="Layout"
      Loaded="Page_Loaded"      
      Title="USKeyboardPage">    
    <Grid x:Name="MainGrid"
          Width="auto"
          Height="auto"
          Focusable="True">
    <!...Row and column definitions are defined...>
     <kb:KeyboardButton Name="Button_Q"
                               Width="auto"
                               Height="auto"
                               Grid.Column="3"                               
                               IsCapsOn="{Binding Path=IsCapsPressed}"
                               IsShiftOn="{Binding Path=IsShiftPressed}"
                               Focusable="True"
                               Style="{StaticResource KeyboardButtonStyle}"
                               Click="NonModifierClick"
                               DataContext="{Binding ElementName=Keyboardwnd}"></kb:KeyboardButton>        
    </Grid>
<page>

//window.xaml
<Window x:Class="Philips.PmsUS.VirtualKeyboard.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"               
        Title="KeyboardWindow"
        x:Name="Keyboardwnd"        
        Height="581"
        Width="1392"
        Topmost="False"
        Loaded="Window_Loaded"
        FocusManager.IsFocusScope="True"
        WindowStartupLocation="Manual"
        Background="{DynamicResource KeyboardBackgroundBrush}">   
    <Grid x:Name="LayoutRoot">
        <Frame x:Name="LayoutHolder"
               Source="Resources\Layouts\USKeyboardPage.xaml"
               ></Frame>            
    </Grid>
  </Window>

//mainwindow.xaml.cs
#region dependency properties
        //the below dependency properties are used for modifier keys
        public static readonly DependencyProperty IsCapsPressedProperty = DependencyProperty.Register("IsCapsPressed", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(new PropertyChangedCallback(SetCapsState)));
        public static readonly DependencyProperty IsShiftPressedProperty = DependencyProperty.Register("IsShiftPressed", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(new PropertyChangedCallback(SetShiftState)));
        public static readonly DependencyProperty IsGlobePressedProperty = DependencyProperty.Register("IsGlobePressed", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(new PropertyChangedCallback(SetGlobeState)));
        #endregion

但上面的数据上下文绑定不起作用。请帮助。

4 个答案:

答案 0 :(得分:0)

尝试设置Window的DataContext。在窗口的构造函数中,在InitializeComponents()之后执行DataContext = this;

由于

答案 1 :(得分:0)

不确定问题是什么。
如果你的意思是:

Binding ElementName=Keyboardwnd

由于ElementName不在该页面上,因此无法正常工作。

不确定依赖关系属性的连接细节,但您可以将MainWindow的引用传递给页面。
不要在XAML中设置框架页面 将其设置在后面的代码中,以便您可以保留对它的引用并传递它。

USKeyboardPage uSKeyboardPage;
uSKeyboardPage = new USKeyboardPage(this);
LayoutHolder.Content = uSKeyboardPage;

USKeyboardPage必须有一个ctor才能收到MainWindow

Public USKeyboardPage(MainWindow main) ...

答案 2 :(得分:0)

我猜你没有使用mvvm? mvvm的一个常见问题是在视图模型之间进行通信(它有效地保存了视图绑定的数据)。这个问题的一个常见解决方案是使用诸如mvvm light之类的消息传递服务来发布消息,其中说某些值已被更新/动作执行/无论如何。任何其他有兴趣了解这一点的观点都会订阅该消息,然后当收到消息时,您可以在本地更新该值。

看不出任何原因你无法发布和订阅后面代码中的消息,你只需要一个消息服务。

答案 3 :(得分:0)

Nitin在这里有一个正确的/部分答案,但是由于您正在学习WPF,因此我将添加一些颜色。

这里要了解的关键是DataContext从父控件自动级联到子控件。

因此,假设您有两个ViewModel,VM1和VM2,并且具有这样的WPF布局:

Window
- Frame
  - Page
    - Grid
      - KeyboardButton

如果将Window的DataContext设置为VM1,则它将自动向下层叠,以便该布局中的每个控件都将具有一个指向该VM1实例的DataContext。如果然后将Grid的DataContext设置为VM2,则Grid和KeyboardButton将具有VM2:

Window                  <- DataContext is VM1, directly set
- Frame                 <- DataContext is VM1, inherited
  - Page                <- DataContext is VM1, inherited 
    - Grid              <- DataContext is VM2, directly set
      - KeyboardButton  <- DataContext is VM2, inherited 

根据运行方式的不同,有一个例外-Frame控件的性质可能会破坏这种级联效果,以使Page不继承DataContext,但是您可以轻松地将Frame的代码隐藏在后面将Page的DataContext显式设置为它自己的。此处的第二个答案提供了有关如何轻松执行此操作的有用片段:

page.DataContext not inherited from parent Frame?

无论如何,如果以这种方式设置DataContext,则布局中的所有控件都可以非常简单地进行通信,因为它们都在为DataContext查找并修改同一对象(友情提醒:实现并使用INotifyPropertyChanged接口和属性,以便WPF在属性值更改时得到通知,并且它可以自动更新绑定到该属性的任何内容。

如果您确实有单独的DataContext,例如早期获得Grid获取VM2的示例,则可以有很多选择,但是这具体取决于项目的工作方式。例如,如果需要VM2能够与VM1通信,则可以向VM2添加属性以容纳VM1。但是,这里的选择实际上取决于您是否需要执行此操作以及如何运行。