How can I add a Path, that has been defined in the XAML ResourceDictionary, multiple times to a WPF form at runtime?

前端 未结 3 1319
不知归路
不知归路 2021-02-20 04:42

I have a defined path in XAML:


    
        

        
相关标签:
3条回答
  • 2021-02-20 05:00

    Just create style for Path, and apply it.

    0 讨论(0)
  • 2021-02-20 05:08

    I've since found that I had missed an important part of the documentation from MSDN:

    Shareable Types and UIElement Types:

    A resource dictionary is a technique for defining shareable types and values of these types in XAML. Not all types or values are suitable for usage from a ResourceDictionary. For more information on which types are considered shareable in Silverlight, see Resource Dictionaries.

    In particular, all UIElement derived types are not shareable unless they come from templates and application of a template on a specific control instance. Excluding the template case, a UIElement is expected to only exist in one place in an object tree once instantiated, and having a UIElement be shareable would potentially violate this principle.

    Which I will summarise as, that's not the way it works because it’s not creating a new instance each time I execute that code – it’s only creating a reference to the object – which is why it works once but not multiple times. So after a bit more reading I’ve come up with 3 potential ways for a resolution to my problem.

    1) Use a technique to create a deep copy to a new object. Example from other StackOverflow Question - Deep cloning objects

    2) Store the XAML in strings within the application and then use the XAML reader to create instances of the Paths:

    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) Only store the Path data in the Resource Dictionary. Create a new instance of a Path in code, apply the Path data to the new Path and then add the other properties I am interested in manually.

    The XAML - The Path data is stored as a 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>
    

    The C# code to then create an instance and apply the other values:

    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);
    
    0 讨论(0)
  • 2021-02-20 05:11

    There's an easier, built-in way to do this. Set x:Shared="False" on the resource. This will allow it to be reused. Then use it as many times as you want.

    <UserControl.Resources>
        <ResourceDictionary>
            <Path x:Shared="False" x:Key="N44" Width="20" Height="80" Stretch="Fill" Fill="#FF000000" Data="..."/>
        </ResourceDictionary>
    </UserControl.Resources>
    
    0 讨论(0)
提交回复
热议问题