`
clingingboy
  • 浏览: 26757 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
社区版块
存档分类
最新评论

wpf开发常见问题(1)

阅读更多

      经过一段时间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.何时可以取到模板的元素?

在你需要取模板元素的时候,必须保证模板已经加载了.那如何才能保证模板已经加载?

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,这样就万无一失了

Capture

 

现在以上的代码变为

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;
}
分享到:
评论

相关推荐

    WPF开发经典教程

    ### WPF开发经典教程知识点概览 #### 一、WPF基础入门 ##### 1.1 WPF基础之体系结构 - **体系结构概述**:本节深入探讨了Windows Presentation Foundation (WPF)的核心架构,重点讲解了WPF类层次结构以及主要子系统...

    关于WPF开发几个入门文档CHM版

    1. **Programming Windows Presentation Foundation(2005).chm**:这可能是一个早期版本的WPF开发指南,可能涵盖了WPF的基础知识,如控件、布局、数据绑定、样式和模板等,帮助初学者理解WPF的基本架构和编程模型。...

    WPF 开发LED效果

    总结,WPF开发LED效果涉及到的主要知识点有WPF的基本概念、图形绘制、动画系统、自定义控件的创建、XAML布局和事件处理。通过深入学习这个项目的源代码,开发者可以掌握这些技术并将其应用到自己的项目中,实现更...

    wpf开发资料

    1. **MVVM模式**:Model-View-ViewModel(MVVM)是WPF开发中常用的设计模式,它将业务逻辑、数据模型和用户界面分离,提高了代码的可测试性和可维护性。 2. **数据验证**:WPF提供了数据验证机制,允许在用户输入时...

    WPF开发源码.rar

    “初学者必备”这部分提示,这个源代码可能包含了适合初学者理解的基础概念和常见用法,是学习WPF开发的良好起点。通过阅读和分析这些源代码,初学者可以更好地理解WPF的设计原则,掌握如何利用WPF的强大功能来构建...

    WPF MVVM框架 漂亮界面风格的WPF 快速入门WPF实例 功能实用架构清晰易入门 快速入门WPF MVVM开发

    另外,该例子还使用了 MVVM 模式,这是一个常见的 WPF 设计模式。MVVM 模式将视图、模型和逻辑分离开来,使得应用程序更加灵活、可测试和可维护。学习者可以通过这个例子学习到 MVVM 模式的基本原理和实现方法。 这...

    WPF开发框架源码

    **WPF开发框架源码详解** Windows Presentation Foundation(WPF),是微软.NET Framework的一个重要组成部分,主要用于构建桌面应用程序。WPF提供了丰富的用户界面(UI)功能,包括图形、动画、布局、文本处理、...

    WPF 常见文件预览DEMO

    在Windows Presentation Foundation(WPF)中,文件预览功能是一项常见的需求,特别是在开发具有用户友好的图形界面的应用程序时。这个"预览文件-文件类型 支持Word(.doc .docx)、Excel(.xls .xlsx)、PPT(.ppt .pptx...

    WPF开发教程

    ### WPF开发教程知识点梳理 #### 一、WPF基础入门 ##### 1.1 WPF基础之体系结构 - **定义与作用**:这部分内容介绍了Windows Presentation Foundation (WPF) 的体系结构,覆盖了其主要子系统及其交互方式。 - **...

    WPF图形图表开发手册

    本书《WPF图形图表开发手册》由Jack Xu撰写,深入探讨了如何利用WPF和C#来开发各种类型的图形图表,包括常见的柱形图、线图、饼图以及2D和3D图形等。 #### 二、基础知识介绍 - **WPF简介**:WPF是.NET Framework的...

    wpf开发指南(微软Window Presentation Foundation

    开发者可以通过阅读“wpf开发指南”文档,了解详细的概念、示例代码和最佳实践,从而提升WPF应用的开发技能。这份指南可能会涵盖XAML的基本元素、数据绑定的深入理解、控件的定制、布局系统的运用、以及如何创建高效...

    C#+WPF上位机开发课程(模块化与反应式编程)

    在这种编程模式下,程序可以根据数据的变化自动更新视图或其他相关部分,这在WPF开发中尤为重要,因为WPF提供了丰富的工具和技术来支持反应式编程,例如数据绑定和命令模式等。 #### 四、WPF应用环境 根据给定的...

    wpf开发小例子

    这些示例可能还涉及到MVVM(Model-View-ViewModel)设计模式,这是WPF开发中的常见实践。ViewModel作为数据模型和视图之间的桥梁,处理业务逻辑和数据绑定。例如,相机控制、绘图操作和图片处理的逻辑可能都在...

    wpf开发的各种数学公式显示

    在Windows Presentation Foundation(WPF)框架中开发应用时,有时候我们需要展示复杂的数学公式,这通常是教育、科研或者数据分析软件中的常见需求。WPF提供了一种高效且灵活的方式来实现这一目标,使得开发者能够...

    WPF开发教程.doc

    **WPF(Windows Presentation Foundation)开发教程** WPF是微软推出的用于构建Windows桌面应用程序的框架,它基于.NET Framework,提供了一种丰富的用户界面设计能力。本教程将带你深入理解WPF的基础知识,包括其...

    50M-c#wpf最强案例

    《50M-c#wpf最强案例》是一个包含丰富C# WPF开发实践的资源集合,对于想要深入理解和提升C# WPF编程技能的开发者来说,这是一个不可多得的学习宝库。WPF(Windows Presentation Foundation)是.NET Framework的重要...

    WPF开发的3D效果,附源码

    - **深度缓冲**:WPF自动处理深度排序,避免了3D渲染中的遮挡问题。 - **3D图形管线**:理解图形从3D模型到2D像素的转换过程,包括顶点着色、几何处理、光栅化和像素着色等步骤。 通过深入学习和实践这些知识点,...

    WPF 开发教程( 中文版)

    ### WPF 开发教程知识点概览 #### 一、WPF基础入门 ##### 1.1 WPF基础之体系结构 - **体系结构概述**:这...通过学习以上知识点,开发者可以全面掌握WPF开发所需的技能,并能够开发出功能强大且用户友好的应用程序。

    wpf 3D开发工具

    **WPF 3D开发工具概述** WPF(Windows Presentation Foundation)是.NET Framework的一部分,它提供了丰富的用户界面设计和开发能力,包括2D和3D图形。本项目专注于利用WPF进行3D开发,旨在简化并增强3D场景的创建...

    Wpf.rar_.net_wpf .n_wpf csharp_wpf开发入门_wpf教程

    1. **WPF环境搭建**:介绍如何配置开发环境,如安装Visual Studio和.NET Framework。 2. **XAML基础**:讲解XAML语法,包括元素、属性、事件、数据绑定等。 3. **控件使用**:介绍各种常用控件的使用方法,以及如何...

Global site tag (gtag.js) - Google Analytics