C# WPF有效地重用Xaml
我最近一直在做一个使用WPF生成图表的项目。在本文中,我必须在符号旁边显示文本,这些符号说明了与文本相关的信息 为了绘制符号,我最初使用了一些我制作的png图像。在我的图表中,这些图像看起来很模糊,放大后看起来更糟。为了改进这一点,我决定使用矢量而不是rastor图像格式。下面是我从文件路径获取rastor图像的方法:C# WPF有效地重用Xaml,c#,wpf,xaml,C#,Wpf,Xaml,我最近一直在做一个使用WPF生成图表的项目。在本文中,我必须在符号旁边显示文本,这些符号说明了与文本相关的信息 为了绘制符号,我最初使用了一些我制作的png图像。在我的图表中,这些图像看起来很模糊,放大后看起来更糟。为了改进这一点,我决定使用矢量而不是rastor图像格式。下面是我从文件路径获取rastor图像的方法: protected Image GetSymbolImage(string symbolPath, int symbolHeight) { Image symbol =
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
为这个问题的长度道歉。我想记录下我的尝试可能会对有类似问题的人有所帮助
谢谢。史蒂夫
虽然这可能无法回答您的全部问题或直接解决您的问题,但它可能有助于“存储和重用xaml”:您可以使用和类动态加载xaml或将对象写入xaml。我无法估计您是否真的会获得性能优势,但也许值得一试
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);
向史蒂夫问好
虽然这可能无法回答您的全部问题或直接解决您的问题,但它可能有助于“存储和重用xaml”:您可以使用和类动态加载xaml或将对象写入xaml。我无法估计您是否真的会获得性能优势,但也许值得一试
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);
最好的祝愿当您将
画布
包装在用户控件
中时,您的基本工作是创建一个框架模板
。FrameworkTemplate
是一个抽象类,文档中说,“能够实例化FrameworkElement
和/或FrameworkContentElement
对象的树”,这是您的真正目标
FrameworkTemplate
有两个具体的子类:ControlTemplate
和DataTemplate
。在XAML中创建UserControl
将设置其内容,该内容用于构造其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>
这将在项控件的画布中为集合中的每个符号创建画布(您的符号),放置在符号的位置。顶部和符号。左侧属性表示应该放置该符号
通过使用模板选择器和Symbol
类的适当设计,您可以使用数据绑定来构建整个图表
编辑
除了ControlTemplate
和DataTemplate
之外,还有FrameworkTemplate
的其他子类。一个出现在这篇文章中。当你将画布
包装在用户控件
中时,你基本上在做的是创建一个框架模板
。FrameworkTemplate
是一个抽象类,文档中说,“能够实例化FrameworkElement
和/或FrameworkContentElement
对象的树”,这是您的真正目标
FrameworkTemplate
有两个具体的子类:ControlTemplate
和DataTemplate
。在XAML中创建UserControl
将设置其内容,该内容用于构造其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>
这将在项控件的画布中为集合中的每个符号创建一个画布(您的符号),位于符号.Top
和符号.Left
属性指定的位置