1

I have an application that makes use of a canvas that contains several WPF custom components. I'd like to export these components into a XAML file so that it can be fetched by another application but, in order to do that, I need to add prefix qualifiers to the exported components. For example, if I were to export a FrequencyButtonA component, I'd need to output something like

<PanelControls:FrequencyButtonA Frequency="113.123" Width="250"/>

I've tried the following, but I'm getting an exception due to the use of the ':' character:

return new XElement("PanelControls:" + "FrequencyButtonA");

Any ideas? I've found some other questions here in SO which seem to be similar to the problem I'm experiencing (e.g., this link), but not the exact same scenario.

Thanks in advance!

EDIT - More background information: This is an example of the complete output I'd need to produce:

<Border x:Name="CommsPanelBorder"
    Style="{DynamicResource BorderTemplate}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:PanelControls="clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"
    VerticalAlignment="Top">
        <PanelControls:FrequencyButtonB Frequency="113.123" Width="250"/>
        <PanelControls:FrequencyButtonA Frequency="102.3" Width="150"/>

I forgot to mention in my original post that the root node (Border) gets created inside a method. The method then loops through all the elements placed in the canvas and calls a method on said elements that returns an XElement which is later added to the root node. Thus, I need to make the XElements be able to create themselves. The code for the method is as follows:

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "PanelControls";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "{DynamicResource BorderTemplate}"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        IEnumerable<CommsPanelControl> commsPanelControls = editCanvas.Children.OfType<CommsPanelControl>();

        foreach (var commsPanelControl in commsPanelControls)
        {
            XElement xElement = commsPanelControl.AddXElement(root, ns);
            root.Add(xElement);
        }

EDIT 2. Added some code so Reinder can see my current approach:

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "PanelControls";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "{DynamicResource BorderTemplate}"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        XElement xElement = new XElement(ns + "FrequencyButtonA",
            new XAttribute("Frequency", "113.123"),
            new XAttribute("Width", "250"));
        root.Add(xElement);

EDIT 3. Just as a reference, here's a possible solution to my problem. Thanks Reiner for your input!

XNamespace aw = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        XNamespace ns = "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib";
        var root = new XElement(aw + "Border",
            new XAttribute("Style", "{DynamicResource BorderTemplate}"),
            new XAttribute("Name", "CommsPanelBorder"),
            new XAttribute(XNamespace.Xmlns + "x", "http://schemas.microsoft.com/winfx/2006/xaml"),
            new XAttribute(XNamespace.Xmlns + "PanelControls", "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"),
            new XAttribute("VerticalAlignment", "Top")
        );

        XElement xElement = new XElement(ns + "FrequencyButtonA",
            new XAttribute("Frequency", "113.123"),
            new XAttribute("Width", "250"));
        root.Add(xElement);
Community
  • 1
  • 1
Nacho1984
  • 111
  • 6
  • 17

2 Answers2

4

a prefix like PanelControls only makes sense if you declare the namespace that it relates to.

You need to specify this in the node itself or for instance in the root.

// create the root element, with the 'PanelControls' namespace
XNamespace nSpace = "PanelControls";
XElement element = new XElement("root",
          new XAttribute(XNamespace.Xmlns + "PanelControls", nSpace));

element.Add(addXElement("FrequencyButtonA", nSpace ));

...

private static XElement addXElement(string n, XNamespace ns)
{
    return new XElement(ns + n,
        new XAttribute("Frequency", 113.123),
        new XAttribute("Width", 250));
}

the method 'addXElement()' will create the new XElement within the namespace ns, so you end up with this:

<?xml version="1.0"?>
<root xmlns:PanelControls="PanelControls">
    <PanelControls:FrequencyButtonA Width="250" Frequency="113.123"/>
</root>
Reinder Wit
  • 6,490
  • 1
  • 25
  • 36
  • Thanks for your reply, but I'd prefer the output to be more compact, such as the one I've posted. I understand your solution works, but I'd like my resulting XAML to be as concise as possible. Can you suggest a way to get an output like the one in my post? – Nacho1984 Oct 23 '12 at 10:09
  • what are you doing lateron with the returned XElement? – Reinder Wit Oct 23 '12 at 10:19
  • I'm adding it to the root element. At the moment, I create the root object (which is a canvas) in a function and then loop through all the elements it contains and call an instance method on each one of them in order to return themselves as an XElement that is later attached to the root. – Nacho1984 Oct 23 '12 at 10:22
  • then you'll have to define the namespace on that root object, just as ghost stated. I've updated my answer – Reinder Wit Oct 23 '12 at 10:39
  • Thanks for your reply. One thing I don't understand is how to modify the code so that the PanelControls namespace prefix points to "clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib". I've updated my original post with a second edit, where I show a quick test I've done based on your solution. The program compiles, but the output for FrequencyButtonA is not what I want. This is what I'm getting: Any ideas? – Nacho1984 Oct 23 '12 at 11:10
  • Done, I've figured it out! See my updated post. Thanks for all your help on this! – Nacho1984 Oct 23 '12 at 11:25
1
using System;
using System.Xml.Linq;


class Program
{
    static void Main(string[] args)
    {

        XNamespace @namespace = "PanelControls";
        XElement element = new XElement("root",
            new XAttribute(XNamespace.Xmlns + "PanelControls", @namespace),
            new XElement(@namespace + "FrequencyButtonA",
                new XAttribute("Frequency", 113.123),
                new XAttribute("Width", 250)));
        Console.WriteLine(element);
    }
}
Denis
  • 5,894
  • 3
  • 17
  • 23
  • Thanks for your reply. Your solution outputs the code I need for the FrequencyButtonA, however, I forgot to mention in my original post that the root element is created in a different place and then the individual elements (such as the frequency button) get created as stadalone XElement instances that get added to the root. Is there any way to output something like the example I've provided in my original post after the root element has been created? I've tried different approaches, but I'm getting a very verbose output, and I'd like to keep the output compact. – Nacho1984 Oct 23 '12 at 10:26