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

时间:2014-12-10 16:21:29

标签: c# wpf xaml

我正在编写一个需要在Grid控件中包装现有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行中。

如果我将我的行为附加到Rectangle,它会将Rectangle包装在另一个Grid中,并像这样影响可视树:

<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>

我的问题是,在这种情况下,现在包装在新Grid控件中的Rectangle将出现在第0行,而不是容器网格的第1行。 Rectangle的'Grid.Row'附加属性需要重新分配给Wrapper Grid控件。

我的问题是:有没有简单的方法将所有附加属性(例如Grid.Row等)从一个FrameworkElement传输到另一个?或者,任何人都可以建议更好的方法来解决这个问题吗?

我的行为需要确保它所附着的元素被包裹(一个孩子)一个面板控件(理想情况下是一个Grid)。行为需要灵活,并且可以附加到任何类型的元素,任何容器,面板,装饰器等;因此可能有任何需要尊重的附加属性。

仅供参考,我正在使用以下实用程序代码执行包装。它在这个阶段是实验性的,并且只能处理父类型为Panel(Grid)或Decorator(Border)的元素:

        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;
                }
            }
        }

1 个答案:

答案 0 :(得分:0)

我的问题不是很清楚。你到底在做什么?您是否在所有者Grid中动态构建这些子项,或者您是否已经修复了xaml设计?这个附加的dp问题只涉及Grid.Row和Grid.Column属性吗?你能否在一开始就正确地设计你的考试,这样你就不需要&#34;包装&#34;围绕?

请告诉我们更多关于你的最新动态?

我知道这不仅仅是对您的问题的实际答案的评论,而是以下是您如何找到所有附加属性:

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); 
...

所有声音仍然很酷,我建议你先重新考虑你的应用程序设计。