WPF 数据上下文是在设置影响数据上下文表示的属性之前设置的



我有一个向用户表示自定义DataContextUserControl。此控件还具有一个DependencyProperty(带有PropertyChangedCallback),该会影响向用户显示DataContext的方式。

我的自定义UserControlXAML:

<UserControl x:Class="WpfApplication1.MyControl"
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" 
mc:Ignorable="d" 
d:DesignHeight="300" d:DesignWidth="300"
x:Name="Me">
<TextBox Text="{Binding FinalText,ElementName=Me}"/>
</UserControl>

我的自定义UserControl代码隐藏:

using System.Diagnostics;
using System.Windows;
namespace WpfApplication1
{
public partial class MyControl
{
#region Static Fields and Constants
public static readonly DependencyProperty CapitalizeProperty = DependencyProperty.Register(nameof(Capitalize), typeof(bool),
typeof(MyControl), new PropertyMetadata(default(bool), CapitalizePropertyChanged));
public static readonly DependencyProperty FinalTextProperty =
DependencyProperty.Register(nameof(FinalText), typeof(string), typeof(MyControl), new PropertyMetadata(null));
#endregion
#region Properties and Indexers
public bool Capitalize
{
get => (bool)GetValue(CapitalizeProperty);
set => SetValue(CapitalizeProperty, value);
}
public string FinalText
{
get => (string)GetValue(FinalTextProperty);
set
{
Debug.WriteLine($"Setting {nameof(FinalText)} to value {value}");
SetValue(FinalTextProperty, value);
}
}
#endregion
#region Constructors
public MyControl()
{
InitializeComponent();
DataContextChanged += OnDataContextChanged;
}
#endregion
#region Private members
private static void CapitalizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MyControl me)
me.CreateFinalText(me.DataContext as string);
}
private void CreateFinalText(string text)
{
if (text != null)
{
FinalText = Capitalize ? text.ToUpperInvariant() : text.ToLowerInvariant();
}
else
{
FinalText = null;
}
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs args)
{
CreateFinalText(args.NewValue as string);
}
#endregion
}
}

当我通过以下方式使用UserControl时:

<Grid>
<local:MyControl DataContext="Simple string" Capitalize="True"/>
</Grid>

我的调试输出显示以下内容:

将最终文本设置为值简单字符串 将

最终文本设置为值简单字符串

我想知道是否可以在设置DataContext之前设置DependencyPropertyCapitalize?这样,FinalText属性就不会设置两次。

为了使我的问题进一步复杂化,我的实际UserControl需要支持渲染到Image而不附加到Window,这意味着Loaded事件并不总是触发。

我可以添加一个正在使用的DependencyProperty而不是DataContext,但是仍然无法确保在填充所有其他DependencyProperties后填充此新DependencyProperty(示例中Capitalize)

编辑:
正如评论中指出的,不建议使用DataContext,我应该使用另一种Property来设置需要渲染的内容。这很好而且很容易做到,但是仍然不能保证在解析所有其他Properties后解析此新Property
我想这个问题可以重新表述为:如何检测用户控件是否已从 XAML 完全解析?

我想知道是否可以在设置DataContext之前设置依赖属性Capitalize

尝试更改顺序,即在设置DataContext属性之前设置Capitalize属性:

<local:MyControl Capitalize="True" DataContext="Simple string" />

最新更新