代码之家  ›  专栏  ›  技术社区  ›  Sebastian Gray

如何在运行时向WPF窗体添加多次在XAML资源字典中定义的路径?

  •  11
  • Sebastian Gray  · 技术社区  · 15 年前

    我在XAML中定义了一个路径:

    <UserControl.Resources>
        <ResourceDictionary>
            <Path x:Key="N44" Width="20" Height="80" Stretch="Fill" Fill="#FF000000" Data="M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z "/>
        </ResourceDictionary>
    </UserControl.Resources>
    

    我想将其添加到WPF网格中,并像这样执行一次:

    System.Windows.Shapes.Path aPath = new System.Windows.Shapes.Path();
    aPath = (System.Windows.Shapes.Path)this.Resources["N44"];
    LayoutRoot.Children.Add(aPath); 
    

    但是,如果将此代码添加到Button Click事件上,然后单击该按钮两次,则会引发一个错误,说明

    “指定的Visual已经是子级 另一个视觉或根的 合成目标。”

    然后,我尝试创建两个资源实例,但仍然收到相同的错误。以下是我用于此测试的代码:

    private void cmbTest_Click(object sender, System.Windows.RoutedEventArgs e)
      {
       System.Windows.Shapes.Path aPath = new System.Windows.Shapes.Path();
       aPath = (System.Windows.Shapes.Path)this.Resources["N44"];
    
       if (LayoutRoot.Children.Contains(aPath) == true){
        System.Windows.Shapes.Path bPath = (System.Windows.Shapes.Path)this.Resources["N44"];
        LayoutRoot.Children.Add(bPath); 
       }else{
        aPath.Name = "a";
        aPath.Tag = "a";
        LayoutRoot.Children.Add(aPath);
       }
      }
    

    因此,如何在运行时向WPF表单中添加多次在ResourceDictionary中定义的XAML路径?

    3 回复  |  直到 14 年前
        1
  •  13
  •   stone    14 年前

    这是一种更简单、更内置的方法。 在资源上设置x:shared=“false”。这将允许它被重用。然后你想用多少次就用多少次。

    <UserControl.Resources>
        <ResourceDictionary>
            <Path x:Shared="False" x:Key="N44" Width="20" Height="80" Stretch="Fill" Fill="#FF000000" Data="..."/>
        </ResourceDictionary>
    </UserControl.Resources>
    
        2
  •  12
  •   Community Egal    7 年前

    后来我发现我错过了 documentation from MSDN :

    可共享类型和uielement类型:

    资源字典是用于 定义的可共享类型和值 XAML中的这些类型。不是所有类型或 值适用于 资源字典。为了更多 关于哪些类型的信息 在Silverlight中被认为是可共享的, 请参阅资源字典。

    特别是,所有的uielement派生 类型不可共享,除非 来自模板和应用 特定控件上的模板 实例。不包括模板案例, uielement应该只存在 在对象树中的一个位置 实例化,并具有uielement 共享可能会违反 这一原则。

    我总结为,这不是它的工作方式,因为 它没有创建新实例 每次我执行该代码时,它只创建一个对对象的引用,这就是为什么它只能工作一次而不是多次。 所以在多读了一点之后,我想出了三种解决我的问题的潜在方法。

    1) 使用技术创建新对象的深度复制。其他stackoverflow问题示例- Deep cloning objects

    2) 将XAML存储在应用程序中的字符串中,然后使用XAML读取器创建路径的实例:

    System.Windows.Shapes.Path newPath = (System.Windows.Shapes.Path)System.Windows.Markup.XamlReader.Parse("<Path xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'  Width='20' Height='80' Stretch='Fill' Fill='#FF000000' Data='M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z ' HorizontalAlignment='Left' VerticalAlignment='Top' Margin='140,60,0,0'/>");
    LayoutRoot.Children.Add(newPath);
    

    3) 只将路径数据存储在资源字典中。在代码中创建路径的新实例,将路径数据应用于新路径,然后手动添加我感兴趣的其他属性。

    XAML-路径数据存储为streamgeometry:

    <UserControl.Resources>
        <ResourceDictionary>
            <StreamGeometry x:Key="N44">M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z</StreamGeometry>
        </ResourceDictionary>
    </UserControl.Resources>
    

    C代码创建实例并应用其他值:

    System.Windows.Shapes.Path bPath = new System.Windows.Shapes.Path();
    bPath.Data = (System.Windows.Media.Geometry)this.FindResource("N44");
    
    bPath.Width = 20;
    bPath.Height = 80;
    
    bPath.VerticalAlignment = System.Windows.VerticalAlignment.Top;
    bPath.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
    
    left = left + 40;
    
    System.Windows.Thickness thickness = new System.Windows.Thickness(left,100,0,0);
    bPath.Margin = thickness;
    
    bPath.Fill = System.Windows.Media.Brushes.Black;
    LayoutRoot.Children.Add(bPath);
    
        3
  •  3
  •   gimalay    15 年前

    只需为路径创建样式,并应用它。