WPF:将附加属性从一个元素转移到另一个元素



我正在编写一个需要将现有 FrameworkElement 包装在网格控件中的 WPF 行为。

举个例子:

<Grid> <!-- Container Grid -->
  <Grid.RowDefinitions>
    <RowDefinition Height="1*"/>
    <RowDefinition Height="1*"/>
  </Grid.RowDefinitions>
  <Rectangle Height="100" Width="100" Grid.Row="1"/>
</Grid>

这是网格中的简单矩形,包含两行。使用附加属性,矩形设置为显示在网格的第 1 行中。

如果我将我的行为附加到矩形,它会将矩形包装在另一个网格中,并影响可视化树,如下所示:

<Grid> <!-- Container Grid -->
  <Grid.RowDefinitions>
    <RowDefinition Height="1*"/>
    <RowDefinition Height="1*"/>
  </Grid.RowDefinitions>
  <Grid> <!-- Wrapper Grid -->
    <Rectangle Height="100" Width="100" Grid.Row="1"/>
  </Grid>
</Grid>

我的问题是,在这种情况下,现在包装在新的网格控件中的矩形将显示在容器网格的第 0 行,而不是第 1 行。矩形的"网格.行"附加属性需要重新分配给包装网格控制。

我的问题是:有没有简单的方法将所有附加的属性(如Grid.Row等(从一个框架元素转移到另一个框架元素?或者任何人都可以提出解决这个问题的更好方法吗?

我的行为需要确保它附加到的元素被包装(子级(面板控件(理想情况下是网格(。行为需要灵活,并且可以连接到任何类型的元素,在任何容器,面板,装饰器等中;因此,可以拥有任何数量的需要履行的附加财产。

仅供参考,我使用以下实用程序代码来执行包装。它在此阶段是实验性的,只能处理父级为面板(网格(或装饰器(边框(的元素:

        public static FrameworkElement WrapFrameworkElementWithGrid(FrameworkElement elementToWrap)
        {
            if (elementToWrap != null)
            {
                var container = new Grid();
                if (elementToWrap.Parent is Panel)
                {
                    // If the element is in a panel (grid, etc) then remove it,
                    // wrap it and replace it in the Children collection.
                    var panel = elementToWrap.Parent as Panel;
                    int childIndex = panel.Children.IndexOf(elementToWrap);
                    panel.Children.Remove(elementToWrap);
                    container.Children.Add(elementToWrap);
                    panel.Children.Insert(childIndex, container);
                    return container;
                }
                else if (elementToWrap.Parent is Decorator)
                {
                    // If the element is in a decorator (border, etc), then remove
                    // it, wrap it and set the Child as the container.
                    var decorator = elementToWrap.Parent as Decorator;
                    decorator.Child = null;
                    container.Children.Add(elementToWrap);
                    decorator.Child = container;
                    return container;
                }
                else
                {
                    // If the parent is of an unhandled type, then return the original element unwrapped.
                    return elementToWrap;
                }
            }
        }

你的问题对我来说不太清楚。你到底在做什么?您是否在所有者网格中动态生成这些子项,或者您是否已经具有修复 xaml 设计?这个附加的 dp 问题是否仅与网格.行和网格列属性有关?您能否首先正确设计考试,这样您就不需要"绕来绕去"?

请您告诉我们更多关于您在做什么?

我知道这更像是一个评论,而不是对您的问题的实际答案,但以下是您找到所有附加属性的方法:

public IList<DependencyProperty> GetAttachedProperties(DependencyObject obj)
{
    List<DependencyProperty> attached = new List<DependencyProperty>();
    foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(obj,
        new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.All) }))
    {
        DependencyPropertyDescriptor dpd =
            DependencyPropertyDescriptor.FromProperty(pd);
        if (dpd != null && dpd.IsAttached)
        {
            attached.Add(dpd.DependencyProperty);
        }
    }
    return attached;
}

因此,也许您可以在运行时加载 Xaml,然后在决定显示页面之前更改内容。

看看这个例子:

StreamReader mysr = new StreamReader("Page1.xaml");
DependencyObject rootObject = XamlReader.Load(mysr.BaseStream) as DependencyObject;
ButtoninXAML = LogicalTreeHelper.FindLogicalNode(rootObject, "button1") as Button ; 
ButtoninXAML.Click += new RoutedEventHandler(Button_Click); 
...

尽管如此,这一切听起来仍然很酷,我建议您首先重新考虑您的应用程序设计。

最新更新