当声明的XAML列表项何时设置其依赖属性?

7

背景

我正在创建一个自定义的WPF面板。为了帮助布局子项,它使用了一个类似于Grid.RowDefinitions或Grid.ColumnDefinitions的辅助列表,我称之为“布局”。每个布局都有几个依赖属性,子项使用附加属性来确定它们的位置,如下所示。

<Panel>
    <Panel.Layouts>
        <Layout/>
        <Layout Attachment="Right"/>
        <Layout Attachment="Left" Target="0"/>
    </Panel.Layouts>

    <ChildItem Panel.Layout="0"/>
    <ChildItem Panel.Layout="1"/>
    <ChildItem Panel.Layout="2"/>
<Panel/>

显然,这里的细节有所简化,但归纳起来:在“排列”过程发生之前,我需要对添加的布局进行处理。我已经创建了一个自定义集合,并且可以看到添加的项目(如下所示的代码),但这些项目只有它们的默认属性。
LayoutCollection: IList
{
    public int IList.Add(object value)
    {
        // When first starting, this line always returns the default value, not the one set in XAML
        Attachment a = (value as Layout).Attachment;

        // Other code happens below...
    }
 }

然而,当我在面板初始化后查看集合时,属性都已正确设置。这就引出了我的问题:

问题

在XAML和面板初始化之间的过程中,在何时分配项目它们的属性,以及如何分配?我需要找到方法来挂接并运行一些代码。


你需要在关联属性的值被设置/使用之前还是之后进行钩子处理?如果涉及到排列操作,可以查看https://msdn.microsoft.com/de-de/library/system.windows.frameworkelement.arrangeoverride(v=vs.110).aspx。 - MABVT
附加属性(Panel.Layout是附加属性)具有回调函数,您可以使用它来了解何时设置/更改值。您可以在Window类中覆盖该回调。如果您展示创建这些附加属性的代码以及导致问题的特定点,那将很好。然后修复它应该很容易。请参见此处 - Sinatr
1
为什么不在 MeasureOverride 中处理布局,然后再测量和排列子元素呢? - Clemens
@Clemens - 我可以把处理推入MeasureOverride中,那里很合理。但如果我能够在添加时一个一个地处理,这将会变得简单100倍左右。 - bidanshi
@Sinatr - 这就是我遇到问题的地方。这全部都在一个 WPF 面板中(如上面的代码所示)。<Panel.Layouts/> 是面板的自定义属性,它会被填充上你在我提供的 XAML 中看到的 <Layout/> 项。问题在于当它开始运行并且列表被填充时,我在 XAML 中设置的任何值都没有传递过来。当面板加载时,这些项会自动添加,但属性为空或默认值。 - bidanshi
显示剩余2条评论
1个回答

1
我的想法是,WPF的面板布局系统并没有真正设计成按照您希望的方式进行拦截。但是有一种机制可以“同步”您的自定义DependencyProperties。问题是,在布局过程中何时需要使用这些属性?
如果是在ArrangeOverride期间,您必须设置AffectsArrange。或者在MeasureOverride期间设置AffectsMeasure。还有其他一些变体,但我认为这两个可以满足您的要求。
例如,如果您选择了AffectsArrange,并且您的面板被通知List.Add,那么ArrangeOverride将被调用,并且新添加的项可以在您的排列逻辑中使用。

我已经进行了大量的测试,知道在调用OnInitialized时一切都已设置好。您的解决方案提供了一种优雅的方式来解决这个问题。不过我想我会在控件初始化时设置AffectsArrange。 - bidanshi

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