Создание элемента XML с префиксом с помощью XElement

У меня есть приложение, которое использует холст, содержащий несколько пользовательских компонентов WPF. Я хотел бы экспортировать эти компоненты в файл XAML, чтобы его можно было получить другим приложением, но для этого мне нужно добавить квалификаторы префикса к экспортируемым компонентам. Например, если бы мне нужно было экспортировать компонент FrequencyButtonA, мне нужно было бы вывести что-то вроде

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

Я пробовал следующее, но получаю исключение из-за использования символа ':':

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

Любые идеи? Я нашел некоторые другие вопросы здесь, в SO, которые кажутся похожими на проблему, с которой я сталкиваюсь (например, эту ссылку), но не тот же сценарий.

Заранее спасибо!

РЕДАКТИРОВАТЬ. Дополнительная справочная информация: это пример полного вывода, который мне нужно создать:

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

РЕДАКТИРОВАТЬ 2. Добавлен код, чтобы Рейндер мог видеть мой текущий подход:

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

РЕДАКТИРОВАТЬ 3. В качестве справки здесь возможное решение моей проблемы. Спасибо Райнер за ваш вклад!

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

person Nacho1984    schedule 22.10.2012    source источник


Ответы (2)


префикс типа PanelControls имеет смысл только в том случае, если вы объявляете пространство имен, к которому он относится.

Вам нужно указать это в самом узле или, например, в корне.

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

метод addXElement() создаст новый XElement в пространстве имен ns, так что в итоге вы получите следующее:

<?xml version="1.0"?>
<root xmlns:PanelControls="PanelControls">
    <PanelControls:FrequencyButtonA Width="250" Frequency="113.123"/>
</root>
person Reinder Wit    schedule 22.10.2012
comment
Спасибо за ваш ответ, но я бы предпочел, чтобы вывод был более компактным, например, тот, который я опубликовал. Я понимаю, что ваше решение работает, но я хотел бы, чтобы полученный XAML был максимально кратким. Можете ли вы предложить способ получить вывод, подобный тому, что в моем посте? - person Nacho1984; 23.10.2012
comment
что вы делаете позже с возвращенным XElement? - person Reinder Wit; 23.10.2012
comment
Я добавляю его в корневой элемент. На данный момент я создаю корневой объект (который является холстом) в функции, а затем перебираю все элементы, которые он содержит, и вызываю метод экземпляра для каждого из них, чтобы вернуть себя как XElement, который позже присоединен к корень. - person Nacho1984; 23.10.2012
comment
тогда вам нужно будет определить пространство имен для этого корневого объекта, как указано в Ghost. я обновил свой ответ - person Reinder Wit; 23.10.2012
comment
Спасибо за ваш ответ. Я не понимаю, как изменить код так, чтобы префикс пространства имен PanelControls указывал на clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib. Я обновил свой исходный пост вторым редактированием, где я показываю быстрый тест, который я сделал на основе вашего решения. Программа компилируется, но результат для FrequencyButtonA не тот, что мне нужен. Вот что я получаю: ‹FrequencyButtonA Frequency=113.123 Width=250 xmlns=PanelControls /› Есть идеи? - person Nacho1984; 23.10.2012
comment
Готово, я разобрался! Смотрите мой обновленный пост. Спасибо за вашу помощь в этом! - person Nacho1984; 23.10.2012

person    schedule
comment
Спасибо за ваш ответ. Ваше решение выводит код, который мне нужен для FrequencyButtonA, однако я забыл упомянуть в своем исходном сообщении, что корневой элемент создается в другом месте, а затем отдельные элементы (например, кнопка частоты) создаются как отдельные экземпляры XElement, которые добавиться в корень. Есть ли способ вывести что-то вроде примера, который я привел в своем исходном сообщении, после создания корневого элемента? Я пробовал разные подходы, но я получаю очень подробный вывод, и я хотел бы, чтобы вывод был компактным. - person Nacho1984; 23.10.2012