1

I am a newbie to WPF.I have a WPF window and in the same project I have a WPF page.The page contains the keyboard layout to be loaded into the window.The window has a frame whose source is set to the page.Now all the buttons in page are WPF custom controls.These controls have two dependency properties like IsCapsOn and IsShiftOn. These dependency properties when changed changes the text on buttons("a" becomes "A" indicating that caps is pressed). The above dependency properties are binded to dependency properties of mainwindow by name IsCapsPressed and IsShiftPressed. When user presses caps key on mainwindow, IsCapsPressed property changes in the backend and as a result IsCapsOn also has to change due to binding.For this i have to set the data context of buttons in page to mainwindow because dependency properties are defined in it.Following are code 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

But the above Data context binding is not working.Please help.

4

4 回答 4

1

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

谢谢

于 2013-08-30T12:19:44.863 回答
0

不知道问题是什么。
如果你的意思是:

Binding ElementName=Keyboardwnd

这是行不通的,因为 ElementName 不在该页面上。

不确定连接依赖属性的详细信息,但您可以将 MainWindow 的引用传递给页面。
不要在 XAML 中设置框架页面。
在后面的代码中设置它,这样你就可以持有对它的引用并传递它。

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

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

Public USKeyboardPage(MainWindow main) ...
于 2013-08-30T14:18:02.090 回答
0

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

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

于 2013-08-30T15:00:31.103 回答
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 的代码隐藏显式设置页面的 DataContext 到它自己的。这里的第二个答案提供了一个有用的片段,说明如何轻松做到这一点:

page.DataContext 不是从父框架继承的?

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

如果您确实有单独的 DataContext,例如 Grid 获取 VM2 的早期示例,您有很多选择,但这具体取决于您的项目的工作方式。例如,如果您需要 VM2 能够与 VM1 通信,则可以向 VM2 添加一个属性以保存 VM1。但是,这里的选项实际上取决于您是否需要这样做以及您需要它如何工作。

于 2019-07-30T13:23:31.540 回答