Я хотел бы распространять DataContext
вверх от динамически созданного DataTemplate
, размещенного с ContentControl
, такого как следующий:
var myFactory = new FrameworkElementFactory(controlTypeToDisplay);//= typeof(MyControl)
var dctxBinding = new Binding
{
Path = new PropertyPath("DataContext.Dctx"),
Mode = BindingMode.OneWayToSource,
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ContentControl), 1)
};
myFactory.SetBinding(FrameworkElement.DataContextProperty, dctxBinding);
return new DataTemplate() { VisualTree = myFactory };
Однако результат такой привязки равен null
хотя DataContext устанавливается в конструкторе MyControl
.DataContext из MyControl определенно не устанавливается в ноль дальше, конструктор вызывается перед установщиком Dctx
.Как я могу исправить привязку, чтобы свойства MyControl
DataContext и Dctx
всегда были синхронизированы?
Полный минимальный пример проблемы (при правильной работе должны отображаться два текстовых блока "FooBar")):
//MyControl.xaml
<Grid>
<TextBlock Text="{Binding}"/>
</Grid>
//MyControl.xaml.cs
public MyControl()
{
InitializeComponent();
DataContext = "FooBar";
this.DataContextChanged += MyControl_DataContextChanged;
}
private void MyControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("An unexpected change");
}
//MainWindow.xaml
<StackPanel>
<ContentControl ContentTemplate="{Binding DataTemplate}"/>
<TextBlock Text="{Binding Dctx, TargetNullValue='<null>'}" />
</StackPanel>
//MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
private Type controlTypeToDisplay = typeof(MyControl);
public DataTemplate DataTemplate
{ get {/*see first listing*/ } }
private object _dctx;
public object Dctx
{
get { return _dctx; }
set { _dctx = value; RaisePropertyChanged(); }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName]string caller = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
}
}