WPF эффективно использует Xaml - PullRequest
2 голосов
/ 21 мая 2010

Я недавно работал над проектом, использующим WPF для создания диаграммы. В этом я должен показать текст рядом с символами, которые иллюстрируют информацию, связанную с текстом.

Для рисования символов я изначально использовал несколько изображений png, которые я создал. На моей диаграмме эти изображения выглядели размытыми и выглядели хуже только при увеличении. Чтобы улучшить это, я решил использовать векторный, а не растровый формат изображения. Ниже приведен метод, который я использовал для получения растрового изображения из пути к файлу:

protected Image GetSymbolImage(string symbolPath, int symbolHeight)
{
    Image symbol = new Image();
    symbol.Height = symbolHeight;
    BitmapImage bitmapImage = new BitmapImage();
    bitmapImage.BeginInit();
    bitmapImage.UriSource = new Uri(symbolPath);
    bitmapImage.DecodePixelHeight = symbolHeight;
    bitmapImage.EndInit();
    symbol.Source = bitmapImage;
    return symbol;
}

К сожалению, это не распознает векторные форматы изображений. Поэтому вместо этого я использовал метод, подобный следующему, где «путь» - это путь к файлу с векторным изображением в формате .xaml:

public static Canvas LoadXamlCanvas(string path)
{
    //if a file exists at the specified path
    if (File.Exists(path))
    {
        //store the text in the file
        string text = File.ReadAllText(path);                

        //produce a canvas from the text
        StringReader stringReader = new StringReader(text);
        XmlReader xmlReader = XmlReader.Create(stringReader);
        Canvas c = (Canvas)XamlReader.Load(xmlReader);

        //return the canvas
        return c;
    }

    return null;
}

Это сработало, но резко убило производительность при повторном вызове.

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

Я пытался использовать этот метод только при начальной загрузке моего приложения и сохранении полученных холстов в словаре, к которому впоследствии можно было получить доступ гораздо быстрее, но позже я понял, что при использовании холстов в словаре мне придется делать их копии , Вся логика, которую я обнаружил в Интернете, связанная с созданием копий, использует XamlWriter и XamlReader, что опять-таки просто создает проблему с производительностью.

Решение, которое я использовал, состояло в том, чтобы скопировать содержимое каждого изображения .xaml в его собственный пользовательский элемент управления, а затем использовать эти пользовательские элементы управления, где это необходимо. Это означает, что теперь я отображаю векторную графику, и производительность намного лучше.

Однако это решение мне кажется довольно неуклюжим. Я новичок в WPF, и мне интересно, есть ли какой-нибудь встроенный способ хранения и повторного использования xaml в приложении?

Извините за длительность этого вопроса. Я думал, что запись моих попыток может помочь кому-то с подобной проблемой.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 21 мая 2010

То, что вы в основном делаете, когда вы заключаете Canvas в UserControl, создает FrameworkTemplate.FrameworkTemplate - это абстрактный класс, который, согласно документации, «позволяет создавать экземпляры дерева из FrameworkElement и / или FrameworkContentElement объектов», что является вашей реальной целью здесь.

Есть дваконкретные подклассы FrameworkTemplate: ControlTemplate и DataTemplate.Создание UserControl в XAML устанавливает его Content, который используется для создания ControlTemplate, так что каждый раз, когда вы создаете экземпляр UserControl, он создает все объекты в этом шаблоне.

Вывместо этого можно создать ControlTemplate, а затем использовать его при создании какого-либо другого элемента управления.Или - и это, вероятно, лучший подход - вы можете создать DataTemplate.

Например, рассмотрите этот XAML:

<DataTemplate TargetType="Symbol">
   <Canvas Canvas.Top="{Binding Top}" Canvas.Left="{Binding Left}">
      <!-- XAML to construct the symbol goes here -->
   </Canvas>
</DataTemplate>

Теперь вы можете сделать это:

<ItemsControl ItemsSource="{StaticResource SomeCollectionOfSymbolObjects}">
   <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
         <Canvas/>
      </ItemsPanelTemplate>
   </ItemsControl.ItemsPanel>
</ItemsControl>

Это создаст Canvas (ваш символ) в ItemsControl Canvas для каждого Symbol в коллекции, расположенный там, где свойства Symbol.Top и Symbol.Left говорят, что это должно бытьрасположен.

Немного повозившись с селекторами шаблонов и надлежащим дизайном класса Symbol, вы, вероятно, сможете использовать привязку данных для построения всей диаграммы.

Редактировать

Существуют и другие подклассы FrameworkTemplate, кроме ControlTemplate и DataTemplate.Один появляется в этом самом посте.

0 голосов
/ 21 мая 2010

Стив,

хотя это может не дать ответа на весь ваш вопрос или решить вашу проблему напрямую, это может помочь вам в «хранении и повторном использовании xaml»: вы можете динамически загружать XAML или записывать объекты в XAML, используя XamlReader и XamlWriter Классы. Я не могу оценить, действительно ли вы получите преимущество в производительности, но, возможно, стоит попробовать.

Пример из MSDN:

// Create the Button.
Button origianlButton = new Button();
origianlButton.Height = 50;
origianlButton.Width = 100;
origianlButton.Background = Brushes.AliceBlue;
origianlButton.Content = "Click Me";

// Save the Button to a string.
string savedButton = XamlWriter.Save(origianlButton);

// Load the button
StringReader stringReader = new StringReader(savedButton);
XmlReader xmlReader = XmlReader.Create(stringReader);
Button readerLoadButton = (Button)XamlReader.Load(xmlReader);

С наилучшими пожеланиями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...