《Programming WPF》翻译 第4章 5.主从复合(Master-Detail)绑定
我们已经看到绑定一个单独的对象,还看到绑定一个单独的对象列表。另一种非常流行的方式是绑定多个对象列表,尤其是相关的列表。例如,如果你向用户显示一个客户列表,当他们选中其中一个客户,就会显示客户的相关订单,这时,你就会使用主从复合绑定。
主从复合绑定是一种过滤的形式,在主页面的列表部分,客户452设置了过滤器作为联合到从页面数据的参数,例如,客户452的相关订单。
到我们目前的讨论为止,我们并没有客户和订单这样的模型,但是我们已经有了家庭和人的定义,于是可以进一步形式化这些,如示例4-47
示例4-47
public class Families : ObservableCollection<Family> {}
public class Family {
string familyName;
public string FamilyName {
get { return familyName; }
set { familyName = value; }
}
People members;
public People Members {
get { return members; }
set { members = value; }
}
}
public class People : ObservableCollection<Person> {}
public class Person {
string name;
public string Name {
get { return name; }
set { name = value; }
}
int age;
public int Age {
get { return age; }
set { age = value; }
}
}在示例4-47中,我们得到了熟悉的具有Name和Age属性的Person类,聚合在熟悉的People集合中。进一步,我们有Family这样的类,具有FamilyName属性和People类型的Members属性。最后,我们有一个Families集合,聚合了Family类型的对象。换句话说,families包含着members,后者由带有年龄和名称的people组成。。
你可以想象到Families,Family,People以及Person的实例如图4-19所示。
在图4-19中,Families集合构成了主页面的数据,保存着Family类的实例,每一个Family实例中持有一个People类型的Members属性,People类型中保存着Person这样的数据。你可以导入这种数据结构的实例,正如示例4-48所示。
图4-19

示例4-48
<!-- Window1.xaml -->
<?Mapping
XmlNamespace="local" ClrNamespace="MasterDetailBinding" ?>
<Window
xmlns:local="local">
<Window.Resources>
<local:Families x:Key="Families"> //Families是个数组,包含Family元素
<local:Family FamilyName="Stooge"> //数组元素,所以包含在数组Families里
<local:Family.Members>
<local:People>
<local:Person Name="Larry" Age="21" />
<local:Person Name="Moe" Age="22" />
<local:Person Name="Curly" Age="23" />
</local:People>
</local:Family.Members>
</local:Family>
<local:Family FamilyName="Addams">
<local:Family.Members>
<local:People>
<local:Person Name="Gomez" Age="135" />
<local:Person Name="Morticia" Age="121" />
<local:Person Name="Fester" Age="137" />
</local:People>
</local:Family.Members>
</local:Family>
</local:Families>
</Window.Resources>

</Window>在顶级绑定到这些数据,例如,显示这些家庭的姓名,如示例4-49所示。
示例4-49
<!-- Window1.xaml -->
<?Mapping
?>
<Window
>
<Window.Resources>
<local:Families x:Key="Families">
</local:Families>
</Window.Resources>
<Grid DataContext="{StaticResource Families}">

<!-- Families Column -->
<TextBlock Grid.Row="0" Grid.Column="0">Families:</TextBlock>
<ListBox Grid.Row="1" Grid.Column="0"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock TextContent="{Binding Path=FamilyName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>在示例4-49中,我们在Families列(第0行)做了两件事。第一件将标题设置为常量“Families”字符串;第二件是形成了body主体,这是一个Family对象的清单,位于Families集合中,现时每一个家庭的FamilyName属性,正如图4-20所示。
图4-20

图4-20并不是一个主从复合结构,因为选中一个主页面的家庭并不会显示这个家庭联合到的详细信息。为了这么做,我们需要绑定到下一级,如示例4-50所示。
示例4-50
<Grid DataContext="{StaticResource Families}">

<!-- Families Column -->

<!-- Members Column -->
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<TextBlock TextContent="{Binding Path=FamilyName}" />
<TextBlock TextContent=" Family Members:" />
</StackPanel>
<ListBox Grid.Row="1" Grid.Column="1"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Members}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock TextContent="{Binding Path=Name}" />
<TextBlock TextContent=" (age: " />
<TextBlock TextContent="{Binding Path=Age}" />
<TextBlock TextContent=" )" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>在Members列(第1列),我们也设置了标题和主体,但是这次标题绑定到当前选中的Family对象的FamilyName。
同样,回忆在Families列,我们的列表框的源条目通过不带Path属性的Binding语句,绑定到了整个集合。然而,在从页面中,我们想告诉数据绑定引擎,我们想要绑定到当前选中的Family对象的Members属性,这是一个Person对象的列表。图4-21显示了主从绑定的效果。
图4-21

但是,稍等:有点过了。主从绑定并没有在这两个级别停下来,根本没有。你可以走得尽可能深,每一个从页面都是主页面的下一级。为了看到这个效果,让我们多增加一级从页面到我们的数据类,如示例4-51所示。
示例4-51
public class Person {
string name;
public string Name {
get { return name; }
set { name = value; }
}
int age;
public int Age {
get { return age; }
set { age = value; }
}
Traits traits;
public Traits Traits {
get { return traits; }
set { traits = value; }
}
}
public class Traits : ObservableCollection<Trait> {}
public class Trait {
string description;
public string Description {
get { return description; }
set { description = value; }
}
}现在,不由仅家庭有了家庭名和成员——带有姓名和年龄的人,而每一个人都有一组特性,每一个都有其独自的描述。张开我们的xaml一小块,包括了这些特性,如示例4-52所示。
示例4-52
<local:Families x:Key="Families">
<local:Family FamilyName="Stooge">
<local:Family.Members>
<local:People>
<local:Person Name="Larry" Age="21">
<local:Person.Traits>
<local:Traits>
<local:Trait Description="In Charge" />
<local:Trait Description="Mean" />
<local:Trait Description="Ugly" />
</local:Traits>
</local:Person.Traits>
</local:Person>
<local:Person Name="Moe" Age="22" >
</local:Person>

</local:People>
</local:Famil.Members>

</local:Family>

</local:Families>我们可以绑定第3级从页面,如示例4-53所示。
示例4-53
<Grid DataContext="{StaticResource Families}">


<!-- Families Column -->


<!-- Members Column -->


<!-- Traits Column -->
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal">
<TextBlock TextContent="{Binding Path=Members/Name}" />
<TextBlock TextContent=" Traits:" />
</StackPanel>
<ListBox Grid.Row="1" Grid.Column="2"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Members/Traits}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock TextContent="{Binding Path=Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>在Families的列标题中,回想我们没有任何绑定;这个文本是硬编码的:
<TextBlock …>Families:</ TextBlock>在Members的列标题中,我们绑定了当先选中的Family对象FamilyName如下:
<TextBlock … TextContent=”{Binding Path=FamilyName}” />逻辑上讲,你可以认为是对如下进行了扩展:
<TextBlock … TextContent=”{Binding Path=Family.FamilyName}” />这里family是当前选中的Family对象。
取得这一级的更深一级,在具有特性的列标题中,我们将当前选中Family的Members属性绑定到当前选中Person的Name属性,绑定如下:
<TextBlock … 
TextContent=”{Binding Path=Members/Name}” />再次,从逻辑上,你可以把它当作这样的扩展:
<TextBlock … 
TextContent=”{Binding Path=family.Members.person.Name}” />这里family是当前选中的Family对象,person是当前选中的Person对象。绑定表达式“/”担当了对象间的分隔符,每一级的对象假定为“当前选中的”。
列表框的源条目的绑定以同样的方式工作,除非我们想要的是当前选中Person的TRaits集合,而不是Name。我们的多级主从绑定的示例如图4-22所示。
图4-22

《Programming WPF》翻译 第4章 5.主从复合(Master-Detail)绑定的更多相关文章
- 《Programming WPF》翻译 第9章 5.默认可视化
原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...
- 《Programming WPF》翻译 第9章 6.我们进行到哪里了?
原文:<Programming WPF>翻译 第9章 6.我们进行到哪里了? 只有当任何内嵌控件都没有提供你需要的底层行为时,你将要写一个自定义控件.当你写一个自定义控件,你将要使用到依赖 ...
- 《Programming WPF》翻译 第9章 4.模板
原文:<Programming WPF>翻译 第9章 4.模板 对一个自定义元素最后的设计考虑是,它是如何连接其可视化的.如果一个元素直接从FrameworkElement中派生,这将会适 ...
- 《Programming WPF》翻译 第9章 3.自定义功能
原文:<Programming WPF>翻译 第9章 3.自定义功能 一旦你挑选好一个基类,你将要为你的控件设计一个API.大部分WPF元素提供属性暴露了多数功能,事件,命令,因为他们从框 ...
- 《Programming WPF》翻译 第9章 2.选择一个基类
原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...
- 《Programming WPF》翻译 第9章 1.自定义控件基础
原文:<Programming WPF>翻译 第9章 1.自定义控件基础 在写一个自定义控件之前,你需要问的第一个问题是,我真的需要一个自定义控件吗?一个写自定义控件的主要原因是为了用户界 ...
- 《Programming WPF》翻译 第8章 6.我们进行到哪里了?
原文:<Programming WPF>翻译 第8章 6.我们进行到哪里了? 动画可以增强应用程序的交互感.它有利于更平滑的转换--当条目出现或消失的时候.它应该,当然,被用于体验和重新着 ...
- 《Programming WPF》翻译 第8章 4.关键帧动画
原文:<Programming WPF>翻译 第8章 4.关键帧动画 到目前为止,我们只看到简单的点到点的动画.我们使用了To和From属性或者By属性来设计动画--相对于当前的属性值.这 ...
- 《Programming WPF》翻译 第8章 5.创建动画过程
原文:<Programming WPF>翻译 第8章 5.创建动画过程 所有在这章使用xaml举例说明的技术,都可以在代码中使用,正如你希望的.可是,代码可以使用动画在某种程度上不可能在x ...
随机推荐
- vue中v-model的一点使用心得
我的data里面有个值是字典的对象: config_template: {}, 这个值会被后端返回的数据填充,填充后大概是这样的: u 'config_template': { u 'startSh ...
- 转:C#制作ORM映射学习笔记二 配置类及Sql语句生成类
在正式开始实现ORM之前还有一点准备工作需要完成,第一是实现一个配置类,这个很简单的就是通过静态变量来保存数据库的一些连接信息,等同于.net项目中的web.config的功能:第二需要设计实现一个s ...
- 16Aspx.com-将15位身份证转换成18位
//********************************************************************************* //将15位身份证转换成18位时 ...
- HDU 1223 还是畅通过程【最小生成树模板】
还是畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- dedecms 调取当前栏目的链接和 栏目名称
<a href="{dede:field name='typeurl' function=”GetTypeName(@me)”/}" target="_blank& ...
- window脚本命令学习(转)
批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键入批处理文件的名称,或者双击该批处理文件,系统就会调用Cmd.exe按照该文件中各个命令出现 ...
- Git历险记(五)——Git里的分支&合并
分支与合并 在Git里面我们可以创建不同的分支,来进行调试.发布.维护等不同工作,而互不干扰.下面我们还是来创建一个试验仓库,看一下Git分支运作的台前幕后: $rm -rf test_branch_ ...
- 【Java编程】JDBC注入攻击-Statement 与 PreparedStatement
在上一篇[Java编程]建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement我们介绍了怎样使用JDBC驱动建立一个简单的 ...
- openfire常见几类插件开发研究与总结
openfire 的插件可以访问所有openfire的API,这给我们的插件实现提供了巨大的灵活性. 以下介绍几类比较常用的插件集成方式: 基于源码XMPP协议的插件 比如:IQHandler,常用来 ...
- 性能测试脚本开发(LR.NET控件)
性能测试过程中,最耗费经历的就是编写性能测试脚本的过程,在大部分的测试工具中都是采用录制的方式,通过录制产生脚本,然后根据需要进行修改,以及参数化.有些时候为了能够完成某一个功能的脚本,需要将录制下来 ...