如何从XAML获取显式指定的属性

3

我有一个包含网格子元素的循环。对于每个子元素,我想知道哪些属性在XAML代码中已经被明确指定了。我有机会找出吗?

例如:我有一个TextBox

<TextBox Height="150"/>

只有属性Height在XAML代码中给出。我该如何在C#代码中找到它? 换句话说,我不想要TextBox的所有属性,而只想要在XAML中指定的那些属性。


这有点棘手。您需要使用XAMLReader来完成此操作。请查看以下链接:http://msdn.microsoft.com/zh-cn/library/system.xaml.xamlreader(v=vs.110).aspx - dev hedgehog
Snoop 在运行时可以知道属性是否从样式/模板/本地等设置了其值,而无需访问原始的 XAML 文件。我会深入研究 Snoop 的代码,看看它是如何实现的。你需要寻找那些通过 Local 设置其值的属性。 - XAMeLi
谢谢你的回答!我不想使用读取器来阅读XAML代码。也许Snoop也使用了XmlReader...我不知道。但似乎很难找到它。 - peter70
XY 问题。你想用这个做什么? - Federico Berasategui
3个回答

3

这是一个具有挑战性的问题,但幸运的是,我喜欢接受挑战。所以一开始,我找到了DependencyPropertyHelper.GetValueSource方法。该方法接受一个DependencyObject和一个DependencyProperty并返回一个ValueSource struct

ValueSource valueSource = DependencyPropertyHelper.GetValueSource(SomeTextBlock, 
    TextBlock.TextWrappingProperty);
ValueSource struct有一个BaseValueSource枚举属性,其成员如下所示:

enter image description here

这些值与DependencyProperty的优先级列表相关,并指定了更改DependencyProperty值的不同方式。 BaseValueSource枚举实例值为Local意味着使用SetValue方法在本地设置了属性...这也包括使用SetValue方法在代码中设置属性的实例。 框架使用此方法从XAML标记设置值。
唯一的问题是我们现在必须找到特定DependencyObject的所有DependencyProperty的集合,以便我们可以在每个上调用上述方法以查看它是否由SetValue方法设置。 我希望Microsoft会给我们提供一些可以为我们完成此操作的东西,但似乎没有。
经过快速搜索,我在StackOverflow的List properties of a DependencyObject?帖子中找到了使用Reflection进行此操作的方法。 但是,我继续寻找,然后找到了一种更好的方法...一种更好的方法。 我在Visual Studio Forum的Getting list of all dependency/attached properties of an Object问题中找到了它。
如果您在该页面向下滚动并查看Zhou Yong的答案,您可以找到他创建的DependencyPropertyHelper类。 起初,我想“让我只运行此DependencyPropertyHelper.GetValueSource方法以查看我得到什么”,并期望得到的所有DependencyProperty的长列表。
但是,事实证明,这个方法输出的正是您想要的内容。 它仅返回在XAML中实际设置的属性。 在他的代码中,我看到了一个MarkupObject,一个MarkupProperty和一个MarkupWriter。 我以前没有使用过这些,但似乎这实际上是查看为TextBlock定义的XAML。 因此,在帮助您的同时,我也学到了一些新东西... +1好问题。
考虑到这一点,我认为你可以忽略我之前回答中关于ValueSource结构体的部分,直接使用该方法。如果需要更多帮助,请告诉我。

0
你可以在自己的代码中继承 TextBox。然后,你可以重写 PropertyChanged 方法,这样你就能接收到任何属性变化的通知。
public class MyTextBox : TextBox
{
    public MyTextBox()
    {
    }

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        Console.WriteLine(string.Format("Property changed: {0} {1}", e.Property.Name, e.NewValue));

        base.OnPropertyChanged(e);
    }
}

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:MyTextBox x:Name="TB" Height="150"></local:MyTextBox>
</Grid>
</Window>

不幸的是,您也会收到由样式更改的属性

以下是上述代码的结果

属性已更改:UndoManagerInstance MS.Internal.Documents.UndoManager

属性已更改:Instance System.Windows.Documents.TextEditor

属性已更改:XmlnsDictionary System.Windows.Markup.XmlnsDictionary

属性已更改:IWindowService WpfApplication1.MainWindow

属性已更改:Name TB

属性已更改:Height 150

属性已更改:Background #FFFFFFFF

属性已更改:BorderBrush #FFABADB3

属性已更改:Foreground #FF000000

属性已更改:BorderThickness 1,1,1,1

属性已更改:TabNavigation None

属性已更改:FocusVisualStyle

属性已更改:AllowDrop True

属性已更改:PanningMode VerticalFirst

属性已更改:IsFlicksEnabled False

属性已更改:Template System.Windows.Controls.ControlTemplate

属性已更改:XmlNamespaceMaps System.Collections.Hashtable

属性已更改:XmlnsDictionary System.Windows.Markup.XmlnsDictionary

属性已更改:XmlNamespaceMaps System.Collections.Hashtable

属性已更改:IsVisible True

属性已更改:ActualWidth 509

属性已更改:ActualHeight 150

属性已更改:PageHeight 148


0
基于 Sheridan 的 答案 中提供的链接,以下是在 XAML 中获取设置在元素上的所有属性所需的非常小的代码片段:
MarkupWriter.GetMarkupObjectFor(element).Properties

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接