WPF嵌套模板引发的血案

简介: 有些事情看似简单,在进行的过程中往往遇到大的麻烦;有些问题小之又小,但躲在角落里窃笑的它能让你呕血数日。反正我不止一次遇到过这样的情况。 日前我打算在产品中加入吊牌打印的功能,涉及到合格证的制作。大伙都有去商店里买衣服的经历,留意看吊牌的话会看到成分一栏里分成好几个类别,如面料、里料、夹层等,每一类别又有好几个物料占比信息,如面料包含70%的棉和30%的xx纤维。

有些事情看似简单,在进行的过程中往往遇到大的麻烦;有些问题小之又小,但躲在角落里窃笑的它能让你呕血数日。反正我不止一次遇到过这样的情况。

日前我打算在产品中加入吊牌打印的功能,涉及到合格证的制作。大伙都有去商店里买衣服的经历,留意看吊牌的话会看到成分一栏里分成好几个类别,如面料、里料、夹层等,每一类别又有好几个物料占比信息,如面料包含70%的棉和30%的xx纤维。如何能让用户较为方便地设置这些信息呢?我原本打算采用自定义集合控件的方式,但是有些问题不好解决,部分难点问题记录在随笔WPF自定义集合控件概述与遇到的问题中。于是我老老实实采用为ListBox新建Template的方式,期望达到如下效果:

 

毫无疑问,上述效果需要俩ListBox,一个呈现大类,一个呈现小类,还得为它们准备各自的DataTemplate,还需要俩GroupBox,它们各自的HeaderTemplate也要额外处理。我微微一笑,流利地敲出代码的第一版本:

 1 <GroupBox DataContext="{Binding Composition,Mode=TwoWay,Converter={StaticResource compositionConverter}}" 
 2             RenderOptions.BitmapScalingMode="NearestNeighbor" Padding="3">
 3     <GroupBox.HeaderTemplate>
 4         <DataTemplate>
 5             <StackPanel Orientation="Horizontal">
 6                 <TextBlock Text="成分" />
 7                 <!--猜测由于没有给GroupBox.Header赋予Content,因此HeaderTemplate里的控件的DataContext为Null-->
 8                 <!--猜测正确,具体请看WPF GroupBox HeaderTemplate and DataBinding http://stackoverflow.com/questions/2425079/wpf-groupbox-headertemplate-and-databinding-->
 9                 <Button x:Name="PART_AddButton" Height="16" Click="PART_AddButton_Click">
10                     <Button.Content>
11                         <Image Source="pack://application:,,,/View.Extension;Component/Images/plus.png" />
12                     </Button.Content>
13                 </Button>
14                 <Button x:Name="PART_DeleteButton" Height="16" Click="PART_DeleteButton_Click">
15                     <Button.Content>
16                         <Image Source="pack://application:,,,/View.Extension;Component/Images/minus.png" />
17                     </Button.Content>
18                 </Button>
19             </StackPanel>
20         </DataTemplate>
21     </GroupBox.HeaderTemplate>
22     <ListBox x:Name="lbxMateriels" ItemsSource="{Binding}" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Hidden">
23         <ListBox.ItemContainerStyle>
24             <Style TargetType="ListBoxItem">
25                 <Setter Property="Margin" Value="2" />
26                 <Setter Property="Template">
27                     <Setter.Value>
28                         <ControlTemplate TargetType="ListBoxItem">                                                    
29                             <GroupBox Header="{Binding}">
30                                 <GroupBox.HeaderTemplate>
31                                     <DataTemplate>
32                                         <StackPanel Orientation="Horizontal">
33                                             <ComboBox ItemsSource="{Binding MaterielKinds,Source={StaticResource context}}" 
34                                                                     MinWidth="60"
35                                                                     SelectedValue="{Binding KindName}"
36                                                                     SelectedValuePath="Name"
37                                                                     DisplayMemberPath="Name" />
38                                             <Button Height="16" Click="btnAddPercent_Click">
39                                                 <Button.Content>
40                                                     <Image Source="pack://application:,,,/View.Extension;Component/Images/plus.png" />
41                                                 </Button.Content>
42                                             </Button>
43                                             <Button Height="16" Click="btnDeletePercent_Click">
44                                                 <Button.Content>
45                                                     <Image Source="pack://application:,,,/View.Extension;Component/Images/minus.png" />
46                                                 </Button.Content>
47                                             </Button>
48                                         </StackPanel>
49                                     </DataTemplate>
50                                 </GroupBox.HeaderTemplate>
51                                 <ListBox x:Name="lbxMaterielPercents" ScrollViewer.VerticalScrollBarVisibility="Hidden"
52                                             ItemsSource="{Binding MaterielPercents}" BorderThickness="0">
53                                     <ListBox.ItemTemplate>
54                                         <DataTemplate>
55                                             <Grid Margin="0 3 0 0">
56                                                 <Grid.ColumnDefinitions>
57                                                     <ColumnDefinition Width="Auto" />
58                                                     <ColumnDefinition Width="*" />
59                                                 </Grid.ColumnDefinitions>
60                                                 <NumericUpDown Value="{Binding Percent}" Minimum="0" Maximum="100" CustomUnit="%" />
61                                                 <ComboBox ItemsSource="{Binding AvailableMateriels,Source={StaticResource context}}"
62                                                                     SelectedValue="{Binding MaterielName}"
63                                                                     SelectedValuePath="Name"
64                                                                     DisplayMemberPath="Name"
65                                                                     Grid.Column="1" MinWidth="60" Margin="5 0 0 0"/>
66                                             </Grid>
67                                         </DataTemplate>
68                                     </ListBox.ItemTemplate>
69                                 </ListBox>
70                             </GroupBox>
71                         </ControlTemplate>
72                     </Setter.Value>
73                 </Setter>
74             </Style>
75         </ListBox.ItemContainerStyle>
76     </ListBox>
77 </GroupBox>

代码有点多,但结构还算清晰,编译也能通过。但是,在页面加载时抛出了NullReference异常,后台代码设置的断点都没执行到。我任劳任怨地开始排查各段代码,最后发现问题出在上述代码的38行到47行之间,我不敢相信自己的眼睛,于是将异常代码用另写的一个测试按钮<Button Content="Test" />代替,运行无问题。我接着开始重启VS、重启机子、拷贝代码的艰苦旅程,问题依旧。最后我灵光乍现,取消注册Click事件,运行无问题。此时我脆弱的大脑已经不堪思索,在尝试用Command代替Event之前,我将希望投给了Bing(经过xx多年努力,Google已经成功被罢用了),发现有人遇到同我一样的问题——Binding to a converter and having a separate button's event assigned results in a nullreference exception?虽然提问并不十分准确,但描述的问题与我的类似,非常幸运的是,有高手解答了。在查看了相关网址之后,我大致心中有数,在此作一纪录。

问题产生前提:

  • You have a Microsoft .NET Framework 4.0-based Windows Presentation Foundation (WPF) application.
  • In the application, there is one template that is nested inside another template.
  • The inner (nested) template contains a control that specifies a style and an event. The style references a static resource.

解决方法:

  • Set the style reference to a dynamic resource.
  • Set the inner template as a resource for the outer template, and then remove the nest relationship.

 更改后的代码相当简单,我就不贴出来了。

最后,我想把上面的整个GroupBox作为一个DataTemplate放到Resource中供页面元素统一调用。 

1 <DataTemplate x:Key="materielOutGPXTemplate">
2          <GroupBox ……
3 </DataTemplate>

然后同样的异常又抛出来了。也许最外围的DataTemplate也作为一层计算在内,此时第一个GroupBox的HeaderTemplate变成嵌套的内层了,又或许我的这个情况导致了多层嵌套,事情会变得更加复杂?反正我按照前述的两个方法都没能解决该问题,只好只将GroupBox的其余部分放入Resources中。世间事无完美,我只能这么安慰自己了。

转载请注明本文出处:http://www.cnblogs.com/newton/archive/2012/12/30/2839520.html

目录
相关文章
|
2月前
|
开发者 C# 存储
WPF开发者必读:资源字典应用秘籍,轻松实现样式与模板共享,让你的WPF应用更上一层楼!
【8月更文挑战第31天】在WPF开发中,资源字典是一种强大的工具,用于共享样式、模板、图像等资源,提高了应用的可维护性和可扩展性。本文介绍了资源字典的基础知识、创建方法及最佳实践,并通过示例展示了如何在项目中有效利用资源字典,实现资源的重用和动态绑定。
45 0
|
2月前
|
开发者 C# 存储
WPF开发者必读:样式与模板的艺术,轻松定制UI外观,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,样式与模板是实现美观界面与一致性的关键工具。样式定义了控件如字体、颜色等属性,而模板则允许自定义控件布局与子控件,两者均可存储于`.xaml`文件中。本文介绍了样式与模板的基础知识,通过示例展示了如何创建并应用它们来改变按钮的外观,从而提升用户体验。
34 0
|
2月前
|
开发框架 前端开发 JavaScript
在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果
在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果
在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果
|
11月前
|
算法 C# UED
浅谈WPF之控件模板和数据模板
WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。
178 8
WPF-Binding问题-模板样式使用Binding TemplatedParent与TemplateBinding区别
WPF-Binding问题-模板样式使用Binding TemplatedParent与TemplateBinding区别
184 0
|
C# 容器
WPF框架下,窗体的嵌套显示
WPF框架下,窗体的嵌套显示
212 0
WPF ComboBox 数据模板
WPF中的控件,有不少都是需要绑定数据的,例如ComboBox控件可以绑定数据,从下拉列表中进行选择。默认情况下,ComboBox控件绑定的数据从显示上比较单一,只能显示固定的文本信息。而为了更好的突出数据展现效果,这里需要使用到WPF中的另一种强大的功能,即数据模板(DataTemplate )
1201 0
WPF ComboBox 数据模板
|
C#
WPF QuickStart系列之样式和模板(Style and Template)
原文:WPF QuickStart系列之样式和模板(Style and Template) 在WPF桌面程序中,当我们想构建一个统一的UI表现时(在不同操作系统下,显示效果一致),此时我们就需要使用到WPF中的样式和模板技术。
1024 0
|
C#
WPF自定义控件(二)の重写原生控件样式模板
原文:WPF自定义控件(二)の重写原生控件样式模板        话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式。   开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式、风格并不能满足我们的需求,那么我们该怎么办呢?----自定义样式与模板。
1257 0
|
C# 容器
WPF模板(二)应用
原文:WPF模板(二)应用           本次内容来源于电子书,和上一篇一样。 在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模板,DataTemplate是数据模板,他们都派生自FrameworkTemplate抽象类。
802 0