经过一段时间wpf的学习和实际开发.现在与大家分享下,在实际中wpf遇到的一些实际问题.silverlight 2.0正式版已经出来.sliverlight的功能应该与wpf大步分类似。其中的经验照样可以套用到sliverlight上.现在开始.
一.与模板相关问题
1.如何取得模板中的元素?
直切重点
(1)第一步确定控件相关ContentPresenter.给出一个扩展方法
public static childItem FindVisualChild<childItem>(this DependencyObject obj) where childItem : DependencyObject { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child != null && child is childItem) return (childItem)child; else { childItem childOfChild = FindVisualChild<childItem>(child); if (childOfChild != null) return childOfChild; } } return null; }
(2)通过ContentControl控件的ContentTemplate属性的FindName方法获取元素
public static object FindTemplateChild(this ContentControl obj, string name) { ContentPresenter content = obj.FindVisualChild<ContentPresenter>(); object child = obj.ContentTemplate.FindName(name, content); return child; }
进一步用泛型封装
public static childItem FindTemplateChild<childItem>(this ContentControl obj, string name) where childItem : DependencyObject { ContentPresenter content = obj.FindVisualChild<ContentPresenter>(); object child = obj.ContentTemplate.FindName(name, content); if (child != null && child is childItem) return (childItem)child; return null; }
在实际情况中,我们还可能用到winfroms控件,所以再来一个
public static childItem FindFormsTemplateChild<childItem>(this ContentControl obj, string name, FrameworkElement parent) where childItem : System.Windows.Forms.Control { object child = obj.ContentTemplate.FindName(name, parent); if (child != null && child is childItem) return (childItem)child; return null; }
2.如果获取元素父级元素?
public static childItem FindAncestor<childItem>(this Visual visual) where childItem : Visual { while (visual != null && !typeof(childItem).IsInstanceOfType(visual)) { visual = (Visual)VisualTreeHelper.GetParent(visual); } if (visual != null && visual is childItem) return (childItem)visual; return null; }
在你需要取模板元素的时候,必须保证模板已经加载了.那如何才能保证模板已经加载?
3-1确保控件(元素)在页面上出现.这个讲法比较通俗,意思就是要保证模板已经加载完成.给出一个简单的例子(目的,用Tab1的button事件去取得Tab2的ListBox控件的模板)
<Grid> <Grid.Resources> <DataTemplate x:Key="demo"> <Label x:Name="labelCrl" Background="Red" Content="{Binding}"></Label> </DataTemplate> </Grid.Resources> <TabControl> <TabItem Header="Button"> <Button Height="23" Margin="143,0,82,81" Name="button1" VerticalAlignment="Bottom" Click="button1_Click">Button</Button> </TabItem> <TabItem Header="ListBox"> <StackPanel> <ListBox x:Name="boxDemo" ItemTemplate="{StaticResource demo}"></ListBox> <ListBox Margin="10,0,0,5" Name="lb"> <ListBoxItem>Item 0</ListBoxItem> </ListBox> </StackPanel> </TabItem> </TabControl> </Grid>
后端,以下代码是无效,除非第一次进来已经切换过Tab2,模板加载完成后才有效.
private void button1_Click(object sender, RoutedEventArgs e) { //if in different tabitem,I can't fetch the ListBoxItem ListBoxItem obj = boxDemo.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem; ContentPresenter obj2 = boxDemo.FindVisualChild<ContentPresenter>(); Object label = obj.ContentTemplate.FindName("labelCrl", obj2); }
那如何解决这个问题?
(1)利用数据绑定的功能,只更改相关属性,模板则自动更新
(2)不要在button事件中更改ui,定义出你需要更改的属性,然后在控件的Onload事件中更改.如你需要更改Label的BackGround,你可以定义一个属性,然后把上面这段代码提取到ListBox的Onload事件当中.
3-2 利用Dispatcher属性异步等待模板加载完成
在实际开发中,有可能会遇到这种现象,取模板的元素,有时成功有时失败,不同机器配置取模板的速度都会不同. 在未理解Dispatcher的使用之前,为防止模板未加载完成.我利用System.Timers.Timer 来等待模板加载完成.
如下示例,使用一个Timer对象反选一个列表中模板中的元素,如果没有取到对象的话,则重新执行Timer事件(Start方法).因为不在同一线程,所以还是需要调用Dispatcher的BeginInvoke方法,进行异步操作.
private Timer timer; public ItemListView() { timer = new Timer(); timer.Interval = 100; timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); } void timer_Elapsed(object sender, ElapsedEventArgs e) { timer.Stop(); Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(this.UnCheckAll)); } public void UnCheckAll() { if (this.SelectedItem != null) { foreach (var item in this.ItemsSource) { DependencyObject viewItem = this.ItemContainerGenerator.ContainerFromItem(item); if (item != this.SelectedItem) { if (viewItem != null) { CheckBox box = viewItem.FindVisualChild<CheckBox>(); if (box != null) { box.IsChecked = false; } else { timer.Start(); } } } } } }
以上的做法虽然可以解决问题,但并非最好办法.勉强可用.
设置异步请求的优先级别即DispatcherPriority.看一下以下的说明,默认一般都设置为Normal,我们可以设置为Background,这样就万无一失了
现在以上的代码变为
public ItemListView() { this.Loaded+=new RoutedEventHandler(ItemListView_Loaded); } void ItemListView_Loaded(object sender, RoutedEventArgs e) { Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(this.UnCheckAll)); }
这一点很重要,取模板之前最好用Dispatcher的BeginInvoke方法去取模板元素,这样不会出错.
4.如何在后端定义一个默认模板?
在定义模板选择器的时候,如果用户未自定义模板的话,可以简单的在后端定义一个模板,方法如下,此方法并不推荐使用了.
private DataTemplate CreateDefault() { DataTemplate tpl = new DataTemplate(); FrameworkElementFactory box = new FrameworkElementFactory(typeof(CheckBox)); Binding bind = new Binding(); box.SetBinding(CheckBox.TagProperty, bind); box.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler(selectChanged)); tpl.VisualTree = box; return tpl; }
其他方面就看msdn和相关书籍吧,以上方法已经很实用,能解决大部分问题了.
二.数据绑定相关
1.赋值不等于绑定
this.DataContext = this.ViewModel;
一般情况下,一个DataContext是通过赋值来执行的.与其绑定的数据来源均实现INotifyPropertyChanged,以实现双向绑定通知
然后在其DataContext 范围内的元素均能共享这个数据源,进行绑定
this.announceContent.SetBinding(AnnounceDetailView.BackgroundProperty, new Binding("xxx"));
this.announceContent.Background = Brushes.Red;
当进行主从绑定的时候,很容易看到DataContext属性就毫不犹豫的进行赋值操作,这时应该进行绑定操作,不要做了赋值的操作,还在为自己狡辩,我真的绑定了怎么没出效果:)
2.只有依赖属性才可以绑定
数据绑定的类型转换器非常的常用,动不动就需要,有时候你需要传入一个参数,而且是依赖属性。可以参考我这里以前写的一篇
http://www.clingingboy.cn/index.php/archives/36
3.如何用绑定语法绑定整个对象
如果要绑定初始对象,可以这样写.加Path=.跟不加有区别的哦
{Binding Path=.}
4.绑定到字典
顺便把以前写的拿过来
{Binding dd[xxx]}
5.绑定选择对象
(1)先设置SelectedValuePath
(2)绑定SelectedItem
(3)绑定SelectedValue
如果在xmal中以上属性设置无效,需要在后端设置,因为无法判断先设置哪个属性即Selector控件需要选择一个默认的对象.
否则的话可以尝试绑定后更改绑定的对象.
6.绑定的内存泄露问题
看这个http://support.microsoft.com/kb/938416
7.与绑定相关的验证问题
我认为wpf内置的验证还不够方面,在.net 3.5sp1对验证功能进行了一些改善.
这个问题将单独拿出来讨论,我将在这篇随笔里面进行补充,提供给大家一种解决方案,供大家参考。
http://www.cnblogs.com/Clingingboy/archive/2008/08/24/1274934.html
8.绑定数据,但要注意性能.
为了实现绑定,有时会从数据库里面把绑定的数据一次性全部取出来,这样没必要,绑定很好,但也要注意性能.
另外其他的相关数据绑定的可以看msdn,很详细,关键还是多练.
三.资源文件相关
1.编译后的资源文件加载速度更快.
默认wpf提供了多种皮肤,而其是以dll的方式提供了,如PresentationFramework.Luna,一个xp下默认的皮肤.在开发过程中(vista)为了统一界面风格,我们需要加载xp皮肤.
Uri url = new Uri("PresentationFramework.Luna;V3.0.0.0;31bf3856ad364e35;component/themes/luna.normalcolor.xaml", UriKind.Relative); System.Windows.ResourceDictionary resource = (System.Windows.ResourceDictionary)System.Windows.Application.LoadComponent(url); System.Windows.Application.Current.Resources.MergedDictionaries.Add(resource);
同样当我们在开发后期我们应该把我们的资源文件整理到一个项目里面进行编译后进行加载,这样性能优于把资源放在每个相关的xaml中.wpf版本的雅虎通就是这么做的:).
这篇文章可以进行比较.很明显的,推荐看一下.
http://www.codeproject.com/KB/WPF/wpfskins.aspx
2.给资源合理分类
当然是为了更好的管理资源文件了,可以参考下此文.
http://www.paulstovell.com/blog/xaml-and-wpf-coding-guidelines
还同时给出了如何更好的写xaml的方案.
先写到这里,有时间再写第二篇,给大家一个参考
public ReferencedAssemblySkin(string name, Uri resourceUri) : base(name) { this._resourceUri = resourceUri; }
发表评论
-
初始化集合项依赖属性
2008-11-03 13:38 779在wpf自定义属性时,若此属性为集合类型的话,如 ... -
WPF and SL RadioButtonList Tip
2008-11-03 14:03 772在以下情境下.使用数据绑定分离UI与后端Model ... -
wpf datagrid笔记 part 1
2008-12-10 23:35 28501,基本属性 开关基本 ... -
Prism V2之旅(2)
2009-01-07 10:02 1109本篇将介绍Prism中Region的使用. 本篇D ... -
Prism V2之旅(3)
2009-01-07 15:24 798上篇介绍了Region的基本应用,这篇接上篇,继续介绍 ... -
Prism V2之旅(4)
2009-01-07 23:42 898上篇介绍了RegionAdapter的作用及如何如何 ... -
Prism V2之旅(5)
2009-01-13 11:54 1054上篇介绍了WPF的Attach Behavior(附加行 ... -
Prism V2之旅(6)
2009-01-13 15:14 983这篇来讲事件.事件主要用来交互. 监听事件 我订 ... -
prism v2之旅(7)
2009-01-15 23:53 1096这篇继续介绍Module的功能. 第5篇已经介绍过模块的 ... -
XAML Guidelines
2009-01-17 11:31 780http://blogs.msdn.com/jaimer ... -
wpf中xaml的类型转换器与标记扩展
2009-02-02 14:03 2268这篇来讲wpf控件属性的类型转换器 类型转换器 类 ... -
wpf控件设计时支持(3)
2009-02-02 14:12 2735wpf设计时调试 编辑模型 装饰器 1.wpf ... -
wpf控件样式管理示意图
2009-02-04 14:40 1589...
相关推荐
基于wpf技术,封装常用的三维操作,如四元数单位旋转球,三维物体可交互功能,常见模型mesh的自动生成等,看大家的使用情况,好的话会不断完善。
另外,该例子还使用了 MVVM 模式,这是一个常见的 WPF 设计模式。MVVM 模式将视图、模型和逻辑分离开来,使得应用程序更加灵活、可测试和可维护。学习者可以通过这个例子学习到 MVVM 模式的基本原理和实现方法。 这...
WPF 编程的书不多,比较全面适合学习的也就2~3本,这本是书是国外在大牛在实现编程中对WPF出现比较常见问题的总结和提炼。很多内容来自于 Stack Overflow Documentation,对于WPF学习和实现工作开发有很好的参考和...
在WPF开发中窗体大小适应问题经常遇到,内容适应窗体的那是常见的操作。但是窗体的大小由内容的大小定义呢?该案例中确定窗体高度,让宽度随实际内容的宽度进行重新定义使之刚好适应。
14本经典android开发教程【修正上一个文件乱码问题】 http://download.csdn.net/detail/cleopard/5744251 上一个文件: 14本经典android开发教程 http://download.csdn.net/detail/cleopard/5729507 88个经典...
书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍 这本书的电子版网上很难找到,我这是从图书馆下的,...
书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍。 第1章 WPF概述 1.1 Windows图形演化 1.1.1 ...
网上关于WPF的缩略图开发并不常见,我也是琢磨了好久,才做成功了这个,关于WPF的缩略图,希望对大家有所帮助,具有缩略图的一般功能,打开,显示、点击当前图像显示大图,上下张图像。
书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍。 这本书的电子版网上很难找到的,这是我从图书馆下的...
《WPF编程宝典:使用C# 2008和.NET 3.5》在亚马逊网站上...书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍。
书中不仅全面介绍了常见的图形界面编程技术,而且对WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也进行了比较深入的介绍。 第1章 WPF概述 1.1 Windows图形演化 1.1.1 ...
WPF编程宝典 : C#2010版/ (美)Matthew MacDonald著;王德才译 共有 118M,PDF 文档 ...WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也 进行了比较深入的介绍。
WPF编程宝典 : C#2010版/ (美)Matthew MacDonald著;王德才译 共有 118M,PDF 文档 ...WPF中非常有特色的文档和打印、音频和视频、动画、3D图形开发、多线程和插件等内容也 进行了比较深入的介绍。
常见相机(大恒、大华、海康、Basler)SDK的封装特点: 1,接口统一(名字、方法、属性....); 2, 输出脱离了对具体硬件SDK的应用; 3, 本次发布只提供X64 4, 提供的DEMO为VS2010, WPF的形式; 5, DEMO中提供两种方法调用...
WPF 的 XamlBehaviors XAML 行为是一种易于使用的方法,可使用最少的代码向 WPF 应用程序添加常见且可重用的交互性。 XAML 行为的使用受 MIT 许可证管理。 我们正在与以指导行为项目并评估传入的拉取请求。入门从...
XamlFlair XamlFlair库的目标是简化常见动画的实现,并允许开发人员仅用几行Xaml即可轻松添加单个或组合的动画集。内容从Nuget安装平台包NuGet 超人 WPF 宇野 要安装XamlFlair ,请在程序包管理器控制台中运行以下...
描述常见的软件问题,并提供了解决这些问题的重构实践 展示了叮用于测试wpf和silverlight应用程序的模式 在修复缺陷时,确保不会导致意料之外的副作用 展示如何构建具有可测试性的mvc应用程序 共享可用于...
主要介绍了如何搭建新的WPF项目框架,在项目开发中比较常见的开发模式就是MVVM模式,使用MVVM框架开发好处:1、框架较轻,2、学习成本低、3、适用大多数中小型项目,4、相对于微软的prism框架更容易上手,需要的朋友...
Overview | 项目概述该系统具备常见医疗流程,并可以完成患者和医生信息的输入,存储,修改,查询,删除等功能。 每个医生都有自己的密码,有人可以更改数据,有人无法修改,只能查看。 同时,数据也有一定的维护,...