tyr*_*ker 6 wpf datacontext binding wpf-controls
这困扰了我一段时间,我厌倦了解决这个问题.在WPF中,涉及到的"操作顺序"是什么:
所有这些都考虑了嵌套控件和模板(当应用模板时).
我有很多有问题的场景,但这只是一个例子:
自定义用户控件
<UserControl x:Class="UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel>
<Label Content="{Binding Label1}" />
<Label Content="{Binding Label2}" />
</StackPanel>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
用户控制代码隐藏
using System;
using System.Windows;
using System.Windows.Controls;
namespace UserControls
{
public partial class TestUserControl : UserControl
{
public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel1PropertyChanged));
public String Label1
{
get { return (String)GetValue(Label1Property); }
set { SetValue(Label1Property, value); }
}
public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel2PropertyChanged));
public String Label2
{
get { return (String)GetValue(Label2Property); }
set { SetValue(Label2Property, value); }
}
public TestUserControl()
{
DataContext = this;
InitializeComponent();
}
private static void OnLabel1PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
//used for breakpoint
}
private static void OnLabel2PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
//used for breakpoint
}
}
}
Run Code Online (Sandbox Code Playgroud)
窗口使用用户控件
<Window x:Class="Windows.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControls"
>
<StackPanel>
<Label Content="Non user control label" />
<UC:TestUserControl x:Name="uc" Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
窗口的代码隐藏
using System;
using System.Windows;
namespace Windows
{
public partial class TestWindow : Window
{
public String Label2FromWindow
{
get { return "User control label 2"; }
}
public TestWindow()
{
DataContext = this;
InitializeComponent();
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么在这种情况下,为什么用户控件中的"Label2"不能从窗口中获取"Label2FromWindow"的值?我觉得这是一个计时问题,用户控件首先评估其所有表达式,然后窗口稍后评估其表达式,并且用户控件永远不会"通知"窗口的评估值.
这个例子有望说明一个问题,但我真正的问题是:
关于DataContext,属性上的硬编码值,绑定表达式,模板和嵌套控件的操作顺序是什么?
编辑:
HB帮我实现了这个目标.当窗口的DataContext设置为自身时,用户控件将"继承"DataContext.这使得Binding可以在用户控件的属性上工作,但是在用户控件中,绑定到其本地属性将不起作用.当直接在用户控件上设置DataContext时,窗口的绑定到用户控件的属性不再有效,但是用户控件可以绑定到它自己的本地属性.以下是有效的更新代码示例.
用户控制:
<UserControl x:Class="UserControls.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="uc">
<StackPanel>
<Label Content="{Binding ElementName=uc, Path=Label1}" />
<Label Content="{Binding ElementName=uc, Path=Label2}" />
</StackPanel>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
用户控制代码隐藏:
using System;
using System.Windows;
using System.Windows.Controls;
namespace UserControls
{
public partial class TestUserControl : UserControl
{
public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl));
public String Label1
{
get { return (String)GetValue(Label1Property); }
set { SetValue(Label1Property, value); }
}
public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl));
public String Label2
{
get { return (String)GetValue(Label2Property); }
set { SetValue(Label2Property, value); }
}
public TestUserControl()
{
InitializeComponent();
}
}
}
Run Code Online (Sandbox Code Playgroud)
测试窗口:
<Window x:Class="Windows.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControls"
>
<StackPanel>
<Label Content="Non user control label" />
<UC:TestUserControl Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
测试窗口代码隐藏:
using System;
using System.Windows;
namespace Windows
{
public partial class TestWindow : Window
{
public String Label2FromWindow
{
get { return "User control label 2"; }
}
public TestWindow()
{
DataContext = this;
InitializeComponent();
}
}
}
Run Code Online (Sandbox Code Playgroud)