Это беспокоило меня некоторое время, и я устал работать над этой проблемой.Что такое «порядок операций» в WPF:
- Настройка DataContext
- Наследование DataContext
- Оценка значения «жестко закодированного» свойства
- Оценка значения свойства {Binding}
Все это с учетом вложенных элементов управления и шаблонов (когда применяются шаблоны).
У меня был номерпроблемных сценариев, но вот только один пример:
Пользовательский пользовательский элемент управления
<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>
Код пользовательского элемента управления
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
}
}
}
Окно для использования пользовательского элемента управления
<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>
И код для окна
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();
}
}
}
Итак, в этом сценарии, почему «Label2» в пользовательском элементе управления никогда не получает значение из «Label2FromWindow» изокно?Я чувствую, что это проблема синхронизации, когда пользовательский элемент управления сначала оценивает все его выражения, а затем окно оценивает его выражения позже, и пользовательский элемент управления никогда не «уведомляется» об оцененных значениях окна.
надеюсь, что пример полезен для иллюстрации одной проблемы, но мой реальный вопрос:
Каков порядок операций с DataContext, жестко заданными значениями свойств, выражений связывания, шаблонов и вложенных элементов управления?
РЕДАКТИРОВАТЬ:
HB помог мне прийти к этой реализации.Когда DataContext окна установлен на себя, пользовательский элемент управления «наследует» DataContext.Это позволяет Binding работать со свойством пользовательского элемента управления, но тогда в пользовательском элементе управления 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>
Код контроля пользователя:
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();
}
}
}
Окно тестирования:
<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>
Код окна проверки кода:
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();
}
}
}