我是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
但上面的数据上下文绑定不起作用。请帮助。
答案 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。但是,这里的选择实际上取决于您是否需要执行此操作以及如何运行。