0523 截图

https://www.cnblogs.com/joean/tag/wpf/

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

 

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

设置Grid的样式

image

选中后的高亮效果,无非就是设置边框。

然后就是横向显示,需要重写ListBox的ItemsPanel修改为WrapPanel。

image

这样,我们的列表项就可以横向显示,然后设置每个列表项的样式:

image

image

image

TreeView节点前的展开折叠样式

image

image

上面没有设置具体的控件和绑定,而是通过ContentPresenter和ItemsHost来处理的,这样我们就可以结合数据模板来做统一处理,最终将DataTemplate设置的控件自动显示到当前的ContentPresenter和ItemsHost中。

image

 

image

image

 

      image

      果然,这里采用了BootStrapper来完成Run方法,实现应用的启动,我们可以来深挖,看看该文件中都包含什么内容。

      image

image

image

image

image

image

image

   image

        前面介绍的helloWorld里面是采用的Unity容器,这里是MEF,所以要注意的部分,有所不同。这里需要制定MEF可导入导出部件所在的目录或程序集

        image

    image

image

image

      后台代码:

      image

image

       所以我们看到这里,没有任何的业务代码。但是对已IView界面所有的绑定信息,都需要定义到该类中。

      5、Presenter定义。

      image

image

      这样在构造展示器时,我们便可以将IView和ViewModel之间的关系完成绑定。

      6、Module的定义

       image

WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProperty)只能拥有一个binding

这一点可以通过设置binding对象的方法名得知:

public static BindingExpressionBase SetBinding(

      DependencyObject target,

      DependencyProperty dp,

      BindingBase binding

)

方法名是SetBinding而不是AddBinding。如果想要验证一下,也可以在listView1_SelectionChanged事件方法中增加断点,可以监视到。

当多次在同一个对象上设置Binding时,其实并不会增加多余的binding,而是将原来的binding替换掉了,这里以textBox_ContactID为例如下图:

另一个相对的概念:同一个Binding可以同时与多个对象的多个属性(或同一对象的多个属性)形成Binding这一点就不做实践验证了,在MSDN上《Data Binding Overview》中有一段“Binding and BindingExpression”就是讲这个道理的。

也许很多读者已经知道或潜意识里有了这种概念,这里只是做一些强调。

改善优化WPF Binding

下面的内容在修正错误的同时,还将对原有的Binding做一些小小的改进。

在上一篇Blog中,我曾经提到过这样一个问题,在将数据库中的DataTable对象的DefaultView通过XAML语言Binding到listView1对象的ItemsSource上时总是失败。

这里顺便公布一下答案,那就是使用DataContext,不过在动手之前先来梳理一下Binding的一些基本概念及使用方法。

在此之前先来点基础知识,都是MSDN上的内容(不过是E文的),感觉不错所以写下来,供大家阅读:

l典型的Binding具有四个重要组成部分:Binding目标对象(binding target object)、目标对象属性(target property)、Binding数据源(binding source)、Path(用于指明要从数据源中取得的值,就是我们通常写的属性名称)。

   例如:想要把一个员工(Employee)的姓名(EmpName)Binding显示到一个TextBox的Text属性上。

   分析一下其中的4个组成部分:Binding目标对象是TextBox(因为它要最终使用这些数据);目标对象属性是TextProperty(这里要注意,不是Text属性,而是与Text属性相对应的Dependency Property,通常命名是属性名+Property);

   数据源是员工(Employee);Path是EmpName。我的经验是:刚开始使用Binding的时候由于还不熟悉,建议在做之前先在心理把这4个部分对号入座一下,等日后就可以熟悉成自然了。

l    目标对象属性一定要是Dependency Property。由于只有DependencyObject类及其子类能够定义Dependency Property,因此,Binding目标对象就必须是DependencyObject类及其子类了。另一方面反过来说,UIElement(DependencyObject的子类)的大多数属性都有与其对应的Dependency Property,因此,大多数的UIElement属性我们都可以利用其Dependency Property作为目标对象属性从而与数据源建立Binding。

l        再有一点,建立Binding的数据源不一定要是一个CLR对象,也可以是XML数据、ADO.NET对象及DependencyObject。

关于为什么binding的对象一定要是DependencyObject,为什么binding对象的属性一定要是dependency property,这个我就不知道了。

在我第一次看到在XAML中设置Binding的语法时,简直是满头雾水。这东西到底怎么回事,简直就没有章法可循,一会儿ElementName,一会儿Source,还有时什么都没有,就一个{Binding },再有就是Mode,UpdateSourceTrigger等,简直没有头绪。

不过只要打开MSDN,看一下System.Windows.Data.Binding对象,似乎开始有点感觉了,查看Binding对象的属性栏(Properties),你会发现,原来我们在XAML中设置Binding时使用的东西和Binding对象的属性好像都是一一对应的。

确实如此,在XAML中设置Binding就是在这只System.Windows.Data.Binding对象,这里先提醒一下大家。

WPF可不是就这么一个Binding噢,实时上,从BindingBase继承过来的有三个兄弟,Binding只是最常用而已。

找到了binding的老家,相信大家对{Binding ElementName=ElemName, Path=PropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, …}这样的语法应该清楚了吧。

那么{Binding } 及{Binding XXXX}这样的语法呢?其实可以就是等于new Binding()及new Binding(XXXX),其实可以考虑成是分别使用了Binding的两种构造方法,而XXXX的作用自然也就清晰了。

其实和{Binding Path=XXXX}是等价的,都是设置Path属性的。至于这里的Path属性在我们平常使用时其实是用来设置属性名的地方,为什么不直接叫做是PropertyName之类的名字呢?这个又要留着以后思考了。

当一个数据源与一个UIElement形成Binding后,数据源的改变,如果传递给UIElement的指定属性?

同样,当UIElement中指定属性值改变了,如何才能够通知到数据源?要讨论这个问题,需要按数据源来分类进行讨论。这个分类并不是互斥的之前存在一些交集。

因此,同一种Binding场景可能适用于多种情况。下面的内容是来自MSDN中《Binding Sources Overview》中的内容,由于怕翻译的不好而误导大家,所以分类的名称还是使用英文吧。

Using a CLR Class as the Binding Source Object

在典型的Binding情景中,一个CLR 对象作为数据源,将其中一个属性值Binding到某个UIElement的属性上(以上面显示员工姓名的情景为例。

用XAML实现<TextBox Text=”{Binding Source=Employee, Path=EmpName}” />)。当数据源属性值变化了,相应让UIElement中对应属性变化。

需要实现一个中通知机制,最简单的方法是通过实现INotifyPropertyChanged接口完成此操作。具体实现,可以参考MSDN上的文章《How to: Implement Property Change Notification》。

其实就是实现了”public event PropertyChangedEventHandler PropertyChanged;”事件,通常的做法是在上面加封装一个”protected void OnPropertyChanged(string name)”函数。在属性的set方法结尾处,调用此函数实现通知的作用。

如果不实行此接口,则必须自己实现一套通知系统。为你的类中的每一个想要实现通知机制的属性创建一个PropertyChanged模板。

即为你的每一个属性创建一个名为”PropertyNameChanged”事件,其中PropertyName是与这个事件对应的属性名称。然后在属性发生变化是触发这个事件。(听起来就麻烦,我也懒得去实践验证了)

如果以上两种方法都无法实现的话,那么就只好在你认为需要的时候显示的调用UpdateTarget方法来手动更新了。

(这种方法没用过,感觉已经失去了Binding的意义了)

Entire Objects Used as a Binding Source

可以理解为将整个对象作为数据源,与上一个题目的区别很小。

基本上可以认为是原来Binding实现的是数据源属性与UIElement属性之间的Binding,而这次是直接将一个Object对象与一个UIElement的属性进行Binding了。

这种情况可以使用Binding的Source属性指明数据源(假设Employee对象与一个ListBox实现banding,用XAML实现<ListBox ItemsSource=”{Binding Employee}” />),或者还可以将DataContext属性设置为Employee(DataContext属性只有UIElement的一个子类System.Windows.FrameworkElement及其子类才会有)。

这样,在设置ItemsSource时就可以直接使用”{Binding }”这样的语法了。当然,DataContext属性设置成Employee还是需要使用DataContext=”{Binding Employee}”语句的。

有人在这里会嘲笑这一举动实在是啰嗦,事实上,DataContext属性是非常有用的。之所以Binding对象失败而最终不得不使用C#语句进行Binding就是因为没有设置DataContext。

因为,当我们使用{Binding Source= Employee, Path=”EmpName”}设置属性后,WPF查找Source对象是根据Element Tree逐级向上自己的Parent Element查找的,查找每一Element上的DataContext所指定的内容是否包含这一Source内容,并以第一个匹配到的结果作为最终对象。

也就是说,DataContext是按照Element Tree向下继承的,并且决定这WPF在运行时能否找到我们所制定的Source对象。即使我们使用{Binding Path=”EmpName”}的语句也是如此。

比较常见的做法是,当我们有大量的Element需要与一个数据源中的众多属性实现Binding时,我们可以直接在一个公共Parent Element的DataContext上设置这一对象(甚至可以是整个window或page上),这将会极大的加少我们重复的代码量,同时也会是程序更加可读。

当我们需要使用的数据源是一个集合时,如果想要实现改变通知的机制。

同样需要实现一个接口INotifyCollectionChanged用来在集合发生改变时发起,用法单个对象是实现INotifyPropertyChanged接口类似。

首先是将上以前做的不是很好的那一段代码改成XAML语言实现。

将TextBox标签中的Text属性与上面listView1中被选定的记录(listView1.SelectedItem)中对应属性(例如:ContactID)做Binding。

实现后如图所示:

<TextBox Text="{Binding ElementName=listView1, Path=SelectedItem.ContactID}" MinWidth="100" />

看以来代码有点长,而且,下面的几个TextBox也都存在大量的重复内容,这里就可以考虑使用上面所说的DataContext了。

将listView1中被选定的记录(listView1.SelectedItem)作为DataContext放在公共Parent Element上,做法如下:

<WrapPanel Grid.Row="1" Orientation="Horizontal" DataContext="{Binding ElementName=listView1, Path=SelectedItem}">

然后剩下的代码就可以简化很多了:

<StackPanel Orientation="Horizontal" Margin="5,2,5,2">

    <TextBlock Text="ContactID:" TextAlignment="Center" />

    <TextBox Text="{Binding ContactID}" MinWidth="100" />

</StackPanel>

<StackPanel Orientation="Horizontal" Margin="5,2,5,2">

    <TextBlock Text="FirstName:" TextAlignment="Center" />

    <TextBox Text="{Binding FirstName}" MinWidth="100" />

</StackPanel>

<StackPanel Orientation="Horizontal" Margin="5,2,5,2">

    <TextBlock Text="LastName:" TextAlignment="Center" />

    <TextBox Text="{Binding EmailAddress}" MinWidth="100" />

</StackPanel>

<StackPanel Orientation="Horizontal" Margin="5,2,5,2">

    <TextBlock Text="EmailAddress:" TextAlignment="Center" />

    <TextBox Text="{Binding LastName}" MinWidth="100" />

</StackPanel>

原来的SelectionChanged事件处理方法现在已经没有用了,将多余的代码去掉:

<ListView Name="listView1" SelectionChanged="listView1_SelectionChanged" MinWidth="280" >

后台代码中的对应方法也可以删掉了private void listView1_SelectionChanged(object sender, SelectionChangedEventArgs e)

F5 Debug运行一下,结果和原来是完全一样的。

在上一文中无得以选择使用C#实现Binding的部分代码,现在使用XAML语言实现,有几种方案可以选择,通过如下几步实现:

1)      将原先建立给listView1建立Binding那一大串代码删掉,替换成如下代码:

listView1.DataContext = dt.DefaultView;

执行结果如下图所示:

2)      将其与listView1的ItemsSource属性建立Binding,设置每一列的header及DisplayMemberBinding值。

这里由于DataContext的原因,ItemsSource可以写成"{Binding }"的形式而其Children Element也都可以简写成"{Binding ContactID}"这样的形式。

<ListView Name="listView1" MinWidth="280" ItemsSource="{Binding }">

    <ListView.View>

        <GridView x:Name="gridView1">

            <GridView.Columns>

                <GridViewColumn DisplayMemberBinding="{Binding ContactID}" Header="ContactID"></GridViewColumn>

                <GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="FirstName"></GridViewColumn>

                <GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="LastName"></GridViewColumn>

            </GridView.Columns>

        </GridView>

    </ListView.View>

</ListView>

改造完后,运行结果会发现,效果和原来是一样。效率提高了,代码更加简化。

WPF入门系列教程(二) 深入剖析WPF Binding的使用方法(全文完

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值