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.

chriga
  • 798
  • 2
  • 12
  • 29

4 Answers4

1

Try setting the DataContext of the Window. In constructor of your window do DataContext = this; after InitializeComponents().

Thanks

Nitin
  • 18,344
  • 2
  • 36
  • 53
0

Not sure what the question is.
If you mean:

Binding ElementName=Keyboardwnd

That is not going to work as that ElementName is not on that page.

Not sure about the details of wiring up the dependency properties but you can pass a reference of the MainWindow to the page.
Do not set frame page in XAML.
Set it in code behind so you can hold a reference to it and pass this.

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

USKeyboardPage must has a ctor to receive the MainWindow

Public USKeyboardPage(MainWindow main) ...
paparazzo
  • 44,497
  • 23
  • 105
  • 176
0

I'm guessing you're not using mvvm? A common problem with mvvm is communicating between viewmodels (which effectively hold the data the views bind to). One common solution to this problem is to use a messaging service such as included with mvvm light, to post a message saying some value has been updated / action performed /whatever. Any other views interested in knowing about that would subscribe to the message and then when it's recieved you could update the value locally.

Can't see any reason you couldn't post and subscribe to the messages in the code behind, you just need a messaging service.

SteveL
  • 857
  • 10
  • 18
0

Nitin has a correct / partial answer here but I'm just going to add some color, since you're learning WPF.

The critical thing to know here is that DataContext cascades automatically from a parent control to the child control.

So let's say you have two ViewModels, VM1 and VM2, and you have a WPF layout like this:

Window
- Frame
  - Page
    - Grid
      - KeyboardButton

If you set your Window's DataContext to VM1, then it will cascade down automatically so that every control in that layout will have a DataContext pointing to that VM1 instance. If you then set the Grid's DataContext to VM2, then Grid and KeyboardButton would have 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 

Depending on how you're running things, there is an exception to this - the nature of the Frame control can break this cascading effect so that the Page does not inherit the DataContext, but you can easily have the Frame's code-behind explicitly set the Page's DataContext to its own. The second answer here provides a helpful snippet on how to do this easily:

page.DataContext not inherited from parent Frame?

In any event, if you set up your DataContext this way, it makes it very simple for all the controls within the layout to communicate because they're all looking at and modifying the same object for the DataContext (Friendly reminder: implement and use the INotifyPropertyChanged interface and properties so that WPF gets notified when the value of a property change and it can automatically update anything that binds to that property).

If you DO have separate DataContexts like the example early where Grid gets VM2, you have a number of options, but it depends specifically on how your project works. If you need VM2 to be able to communicate with VM1, you could make add a property to VM2 to hold VM1, for example. However, the options here really depend on whether you need to do that and how you would need it to work.

jhilgeman
  • 1,543
  • 10
  • 27