WPF有效地重用Xaml

时间:2010-05-21 10:06:45

标签: c# wpf xaml

我最近一直在使用WPF制作一个图表。在此,我必须在符号旁边显示文字,以说明与文本相关的信息。

为了绘制我最初使用的符号,我制作了一些png图像。在我的图表中,这些图像看起来很模糊,只是在放大时看起来更糟。为了改进这一点,我决定使用矢量而不是rastor图像格式。下面是我用来从文件路径获取rastor图像的方法:

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

不幸的是,这无法识别矢量图像格式。所以我使用了类似下面的方法,其中“path”是格式为.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 :(得分:0)

史蒂夫,

虽然这可能无法回答您的整个问题或直接解决您的问题,但它可能会帮助您“存储和重用xaml”:您可以使用 XamlReader <动态加载XAML或将对象写入XAML / strong>和 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);

祝你好运

答案 1 :(得分:0)

当您将Canvas包裹在UserControl中时,您正在做的事情是创建FrameworkTemplateFrameworkTemplate是一个抽象类,在文档中,“允许实例化FrameworkElement和/或FrameworkContentElement对象的树”,这是你真正的目标。

FrameworkTemplate有两个具体的子类:ControlTemplateDataTemplate。在XAML中创建UserControl设置其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的{​​{1}}中为集合中的每个ItemsControl创建一个Canvas(您的符号),位于SymbolSymbol.Top属性说应该定位它。

通过模板选择器和Symbol.Left类的正确设计,您可以使用数据绑定来构建整个图表。

修改

除了SymbolFrameworkTemplate之外,还有ControlTemplate的其他子类。一个出现在这篇文章中。