【问题标题】:WPF Reusing Xaml EffectivelyWPF 有效地重用 Xaml
【发布时间】:2010-05-21 10:06:44
【问题描述】:

我最近一直在使用 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?

对于这个问题的长度表示歉意。我认为记录我的尝试可能会对遇到类似问题的人有所帮助。

谢谢。

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    当您将Canvas 包装在UserControl 中时,您所做的基本上是创建一个FrameworkTemplateFrameworkTemplate 是一个抽象类,根据文档,“启用FrameworkElement 和/或FrameworkContentElement 对象树的实例化”,这是您的真正目标。

    FrameworkTemplate 有两个具体的子类:ControlTemplateDataTemplate。在 XAML 中创建 UserControl 会设置其 Content,该 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>
    

    这将为集合中的每个SymbolItemsControlCanvas 中创建一个Canvas(您的符号),定位在Symbol.TopSymbol.Left 属性所说的应该定位的位置。

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

    编辑

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

    【讨论】:

      【解决方案2】:

      史蒂夫,

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

      最好的问候

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-09
        • 1970-01-01
        • 2013-08-22
        • 1970-01-01
        • 2013-11-15
        • 1970-01-01
        相关资源
        最近更新 更多