当Generic.xaml遇上BitmapImage:发现一个疑似WPF Bug而又不似Bug的问题
2010-09-30 01:22
381 查看
发现这个有点像Bug又不太像Bug的东西的过程是这样的:
我继承自ContentControl写了一个MyContentControl,在其中定义了一个叫做IconProperty的依赖属性及其对应的CLR属性并且在其静态构造中调用了DefaultStyleKeyProperty.OverrideMetadata方法,代码很少,看起来是这个样子的:
class MyContentControl : ContentControl { static MyContentControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MyContentControl), new FrameworkPropertyMetadata(typeof(MyContentControl))); } public ImageSource Icon { get { return (ImageSource)GetValue(IconProperty); } set { SetValue(IconProperty, value); } } public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(MyContentControl)); }
其中的Icon属性声明类型为ImageSource,目的简单明了,当然就是给这个控件加个图标了。
然后再给这个自定义控件定义一个放在Generic.xaml里的Template,一样很简单,只是用一个StackPanel把它的Icon和Content包起来,代码是这样的:
<Style TargetType="{x:Type local:MyContentControl}"> <Style.Setters> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:MyContentControl}"> <StackPanel> <Image Source="{TemplateBinding Icon}" Stretch="Fill"/> <ContentPresenter Content="{TemplateBinding Content}"/> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style.Setters> </Style>
然后定义一个窗体,其中有一个Canvas和一个Button,点击Button时把Canvas清空然后再向其中加500个位置随机的自定义控件,这部分代码是这样的:
canvas.Children.Clear(); Random random = new Random(); for (int i = 0; i < 500; i++) { MyContentControl marker = new MyContentControl { Content = i, Icon = bitmap }; marker.SetValue(Canvas.LeftProperty, (double)random.Next(0, (int)canvas.ActualWidth)); marker.SetValue(Canvas.TopProperty, (double)random.Next(0, (int)canvas.ActualHeight)); canvas.Children.Add(marker); }
其中的bitmap是窗体的一个私有字段,它关联了一张小箭头式的png图片(这个bitmap是窗体的私有字段或者是方法中的局部变量会对结果有影响,这点稍后说)。
再然后运行程序玩一下吧,点一下Button之后是这样的:
看起来蛮正常的。
但是试着多点几次Button之后发现不对劲了,怎么几乎每一次都比上一次慢呢?
于是就又在加入500个控件的地方监视了一下时间,代码是这样的:
Stopwatch watch = new Stopwatch(); watch.Start(); this.Dispatcher.BeginInvoke(new Action(() => { this.Title = watch.ElapsedMilliseconds.ToString(); if (count <= 10) { ClearAndAddMarkers(); } else { count = 0; } count++; }), DispatcherPriority.Loaded);
计时器在canvas的Children填充之后开始,在Dispatcher的Loaded时停止,这样确保记录下来的时间是用来Render的时间而不是填充集合的时间。把这个清空、填充、计时的过程连续跑十次,把记录下来的时间写到窗体的Title上。
在运行一下,点Button,观察一下Window的Title,先是400多毫秒,然后600多,800多......最后一次用了1300多。当然,如果您机子配置太好的话得把加入自定义控件的数量调大一点。
好奇怪啊好奇怪,我开始认定是代码写的有问题(确实也是有一点,不过不是关键),但是找来找去找不到。于是试着把Generic.xaml改了下名字,不让它自动应用,然后在窗体里面引用这个改了名的资源字典。结果,怪事发生了,每次的时间稳定在了400毫秒左右。
这样看起来好像是WPF对Generic.xaml这种方式的处理有问题了,可以疑似为是个Bug。那为什么标题又说不似Bug呢?
这就涉及到前面说的bitmap了,如果去掉这个私有字段而是在填充canvas的Children的时候每次new一个新的BitmapImage来赋值给每一个自定义控件的Icon的话,也可以把每次的时间维持在400毫秒左右,所以又说它不太像个Bug。
如果有哪位遇到了类似的问题不妨试一下不要用Generic.xaml,改用自己命名的普通资源字典来试一下;又或者是不要让窗体hold住bitmap这个资源不放手,每次new一个BitmapImage试一下。
但是无论如何,同一个Template定义在Generic.xaml中自动应用和定义在普通资源字典中手动引用这两种方式会导致程序的性能不同终究是个奇怪的问题,希望能有高手给出更好的解决方案和解释。
PS:我试过了在.NET 3.5和.NET 4下分别用Debug和Release编译,也试过了在VS中运行和脱离VS独立运行,都是有问题的。
另外,还试过了打微软发布的KB981107这个补丁,一样没有用。
下载代码
相关文章推荐
- 当Generic.xaml遇上BitmapImage:发现一个疑似WPF Bug而又不似Bug的问题
- 发现微软VS工具的一个问题,不知算不算是BUG
- 发现WPF在Windows 7 的一个BUG ,多点触摸开发的注意了
- 发现ASP.NET2.0母版页和主题的一个小问题,不知道是不是不BUG
- 通过View.post()获取View的宽高引发的两个问题:1post的Runnable何时被执行,2为何View需要layout两次;以及发现Android的一个小bug
- 瞎猫碰死老鼠:在ASP里面发现的一个问题,是不是BUG呢?
- 发现一个hibernate针对derby数据库的问题bug,及解决办法
- 周末发现一个BUG,时有时无,一出程序就崩溃,郁闷了好久,终于跟出来来了,记之,提醒自己今后一定规范编写,只要规范,绝对不会出问题
- 今天发现一个bug,不知道是什么问题,printf的问题吗,还是什么。先记下!
- 通过View.post()获取View的宽高引发的两个问题:1post的Runnable何时被执行,2为何View需要layout两次;以及发现Android的一个小bug
- 刚发现一个BUG,模态对话框url中含有#时出现的问题
- 今天工作中发现一个问题,看算不算BUG,如何解释这种现象。
- 发现一个问题,可能是Sql Express 2005的Bug
- 最近调试HEVC中码率控制, 发现HM里面一个重大bug
- [置顶]Win2012R2的一个Bug安装群集后可能引发的软件崩溃问题及相应补丁
- 前WPF PM 用WPF写的一个XAML即时编辑器 - kaxaml
- Android源码Transition.java中发现一个小bug
- 发现ExtJs Chart的一个Bug
- 我ms发现了jquery的一个bug
- ext上传文件,服务端返回json时发现的一个问题