1. DatePicker 和新的 DataGrid
  2. 用户与 DataGrid 中日期列的交互给我造成了很大的麻烦。 我通过将一个 Data Source 对象拖动到 WPF 窗口上,创建了一个 DataGrid 设计器的默认行为是为该对象中的每个 DateTime 值创建一个 DatePicker 例如,下面是为一个 DateScheduled 字段创建的列:
  3.  
  4. <DataGridTemplateColumn x:Name=" dateScheduledColumn"
  5. Header="DateScheduled" Width="">
  6. <DataGridTemplateColumn.CellTemplate>
  7. <DataTemplate>
  8. <DatePicker
  9. SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
  10. ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
  11. </DataTemplate>
  12. </DataGridTemplateColumn.CellTemplate>
  13. </DataGridTemplateColumn>
  14.  
  15. 这一默认行为对编辑造成不便。 编辑时现有行不会更新。 DatePicker 不会在 DataGrid 中触发编辑,这表示数据绑定功能不会将所做的更改推送至基础对象。 通过向 Binding 元素添加 UpdateSourceTrigger 属性并将属性值设置为 PropertyChanged,可以解决这个特定的问题:
  16.  
  17. <DatePicker
  18. SelectedDate="{Binding Path= DateScheduled, Mode=TwoWay,
  19. ValidatesOnExceptions=true, NotifyOnValidationError=true,
  20. UpdateSourceTrigger=PropertyChanged}" />
  21.  
  22. 不过,添加这些新行后,DatePicker 不能触发 DataGrid 编辑模式的问题变得更加严重。 DataGrid 中,新行由 NewRowPlaceHolder 表示。 首次编辑新行中的单元格时,编辑模式会在数据源中触发插入(再次说明,不是在数据库中,而是在内存中的基础源中)。 因为 DatePicker 不触发编辑模式,所以这不会发生。
  23.  
  24. 因为我的行中的日期列恰好是第一列,所以我发现了这个问题。 我本来想使用它来触发该行的编辑模式的。
  25.  
  26. 所示为一个新行,在其中的第一个可编辑列中输入了日期。
  27.  
  28. 在新行占位符中输入日期值
  29.  
  30. 但在编辑下一列中的值之后,前一编辑值丢失,如图 所示。
  31.  
  32. 修改新行中 Task 列值之后日期值丢失
  33.  
  34. 第一列中的键值变为 ,刚刚输入的日期值变为 //。 编辑 Task 列最终会使 DataGrid 在数据源中添加一个新实体。 ID 值变为整数(默认值 ),日期值变为 .NET 默认的最小日期 //。 如果我为此类指定过默认日期,则用户输入的日期将变为此类的默认日期,而不是 .NET 的默认日期。 请注意,Date Performed 列中的日期没有更改为其默认值。 这是因为 DatePerformed 是可以为 Null 的属性。
  35.  
  36. 那么,现在用户是不是必须回去重新修复 Scheduled Date 我相信用户肯定不愿意这样做。 这个问题困扰了我一段时间。 我甚至曾将该列改成 DataTextBoxColumn,但之后我必须处理 DatePicker 起保护作用的验证问题。
  37.  
  38. 最后,WPF 团队的 Varsha Mahadevanset 给我指出了正确的道路。
  39.  
  40. 通过利用 WPF 的组合性质,可以对此列使用两个元素。 DataGridTemplateColumn 不仅有 CellTemplate 元素,还有 CellEditingTemplate 我没有要求 DatePicker 控件触发编辑模式,而只在已经编辑时使用 DatePicker 为了在 CellTemplate 中显示日期,我切换到了 TextBlock 下面是 dateScheduledCoumn 的新 XAML
  41.  
  42. <DataGridTemplateColumn x:Name="dateScheduledColumn"
  43. Header="Date Scheduled" Width="">
  44. <DataGridTemplateColumn.CellTemplate>
  45. <DataTemplate>
  46. <TextBlock Text="{Binding Path= DateScheduled, StringFormat=\{0:d\}}" />
  47. </DataTemplate>
  48. </DataGridTemplateColumn.CellTemplate>
  49. <DataGridTemplateColumn.CellEditingTemplate>
  50. <DataTemplate>
  51. <DatePicker SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
  52. ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
  53. </DataTemplate>
  54. </DataGridTemplateColumn.CellEditingTemplate>
  55. </DataGridTemplateColumn>
  56.  
  57. 请注意,我不再需要指定 UpdateSourceTrigger 我对 DatePerformed 列也进行了同样的更改。
  58.  
  59. 现在,这些日期列一开始是简单文本,在您进入该单元格后才切换到 DatePicker,如图 所示。
  60.  
  61. DateScheduled 列同时使用 TextBlock DatePicker
  62.  
  63. 在新行上面的行中没有 DatePicker 日历图标。
  64.  
  65. 但这还是有点不对。 开始编辑这一行时仍然会得到默认的 .NET 值。 这时,您就可以从在基础类中定义默认值受益。 我修改了 ScheduleItem 类的构造函数,使之将新对象初始化为当天日期。 如果从数据库检索到数据,它将覆盖该默认值。 我的项目使用了实体框架,因此类会自动生成。 不过,生成的类是分部类,这样,我就可以将此构造函数添加到附加的分部类中:
  66.  
  67. public partial class ScheduleItem
  68. {
  69. public ScheduleItem()
  70. {
  71. DateScheduled = DateTime.Today;
  72. }
  73. }
  74.  
  75. 现在,当我通过修改 DateScheduled 列开始在新行占位符中输入数据时,DataGrid 会为我创建一个新的 ScheduleItem,并且在 DatePicker 控件中显示默认值(当天日期)。 现在,当用户继续编辑此行时,输入的值会继续有效。
  76.  
  77. 减少用户在编辑时需要点击的次数
  78. 两部分模板的一个弊端是必须点击单元格两次才能触发 DatePicker 这会对数据输入人员造成不便,特别是对那些习惯于使用键盘输入数据而不使用鼠标的人员。 因为 DatePicker 位于编辑模板中,所以除非触发编辑模式,否则它不会获得焦点(这是默认行为)。 这是针对 TextBox 进行的设计,很适合 TextBox 使用。 但这种设计不太适用于 DatePicker 可以结合使用 XAML 和代码来强制 DatePicker 在用户切换到该单元格时准备好键入。
  79.  
  80. 首先,需要在 CellEditingTemplate 中添加一个 Grid 容器,使它成为 DatePicker 的容器。 然后,可以使用 WPF FocusManager 强制此 Grid 在用户进入该单元格时成为单元格焦点。 下面是作为 DatePicker 容器的新 Grid 元素:
  81.  
  82. <Grid FocusManager.FocusedElement="{Binding ElementName= dateScheduledPicker}">
  83. <DatePicker x:Name=" dateScheduledPicker"
  84. SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
  85. ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
  86. </Grid>
  87.  
  88. 请注意,我为 DatePicker 控件提供了一个名称,并使用 FocusedElement Binding ElementName 指向了该名称。
  89.  
  90. 现在请将注意力转到包含此 Date-Picker DataGrid,注意,我添加了三个新属性(RowDetailsVisibilityModeSelectionMode SelectionUnit)和一个新的事件处理程序 (SelectedCellsChanged):
  91.  
  92. <DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
  93. ItemsSource="{Binding}" Margin="12,12,22,31"
  94. Name="scheduleItemsDataGrid"
  95. RowDetailsVisibilityMode="VisibleWhenSelected"
  96. SelectionMode="Extended" SelectionUnit="Cell"
  97. SelectedCellsChanged="scheduleItemsDataGrid_SelectedCellsChanged">
  98.  
  99. DataGrid 进行的更改会启用当用户选择该 DataGrid 中的新单元格进行通知的功能。 最后,需要确保当用户执行此操作时 DataGrid 确实进入编辑模式,这会在 DatePicker 中向用户提供必要的光标。 scheduleItemsDataGrid_SelectedCellsChanged 方法将提供这最后一部分逻辑:
  100.  
  101. private void scheduleItemsDataGrid_SelectedCellsChanged
  102. (object sender,
  103. System.Windows.Controls.SelectedCellsChangedEventArgs e)
  104. {
  105. if (e.AddedCells.Count == ) return;
  106. var currentCell = e.AddedCells[];
  107. string header = (string)currentCell.Column.Header;
  108.  
  109. var currentCell = e.AddedCells[];
  110.  
  111. if (currentCell.Column ==
  112. scheduleItemsDataGrid.Columns[DateScheduledColumnIndex])
  113. {
  114. scheduleItemsDataGrid.BeginEdit();
  115. }
  116. }
  117.  
  118. 请注意,在类声明中,我将常量 DateScheduledColumnIndex 定义为 ,即该列在网格中的位置。
  119.  
  120. 完成这些更改后,最终用户会很满意。 我费了很大心思才找出使 DatePicker DataGrid 内出色工作的正确 XAML 和代码元素组合,希望这可以帮助您避免经历同样的困难。 现在,UI 以用户熟悉的方式工作了。
  121.  
  122. 使受限 ComboBox 显示旧值
  123. 获取在 DataGridTemplateColumn 中对元素分层的价值之后,我再次考虑了另一个我几乎已经放弃的 DataGrid-ComboBox 列相关问题。
  124.  
  125. 编写这一特定应用程序的目的是为了用旧数据替换旧应用程序。 旧应用程序允许用户不经太多控制输入数据。 在新应用程序中,客户端要求通过下拉列表对一些数据输入进行限制。 通过使用字符串集合很容易提供下拉列表的内容。 难点在于仍要显示旧数据,即使此数据不包含在新的限制列表中也是如此。
  126.  
  127. 我首先尝试使用 DataGridComboBoxColumn
  128.  
  129. <DataGridComboBoxColumn x:Name="frequencyCombo"
  130. MinWidth="" Header="Frequency"
  131. ItemsSource="{Binding Source={StaticResource frequencyViewSource}}"
  132. SelectedValueBinding=
  133. "{Binding Path=Frequency, UpdateSourceTrigger=PropertyChanged}">
  134. </DataGridComboBoxColumn>
  135.  
  136. 在代码隐藏文件中定义源项:
  137.  
  138. private void PopulateTrueFrequencyList()
  139. {
  140. _frequencyList =
  141. new List<String>{"",
  142. "Initial","2 Weeks",
  143. "1 Month", "2 Months",
  144. "3 Months", "4 Months",
  145. "5 Months", "6 Months",
  146. "7 Months", "8 Months",
  147. "9 Months", "10 Months",
  148. "11 Months", "12 Months"
  149. };
  150. }
  151.  
  152. _frequencyList 绑定到另一方法中的 frequencyViewSource.Source
  153.  
  154. 在无数种可能的 DataGridCombo-BoxColumn 配置中,我找不到任何办法来显示可能已经存储在数据库表的 Frequency 字段中的不同值。 我就不一一列举我试过的所有解决方法了,其中一个是将这些额外的值动态添加到 _frequencyList 底部,然后根据需要删除它们。 我并不喜欢这个解决方法,但恐怕我不得不接受它。
  155.  
  156. 我知道编写 UI WPF 分层方法必须为此提供一种机制,并且已经解决了 Date-Picker 问题,因此我意识到可以对 ComboBox 使用相似的方法。 这个技巧的第一部分是避免使用华而不实的 DataGridComboBoxColumn,而是使用更经典的将 ComboBox 嵌入 DataGridTemplateColumn 内部的方法。 然后,利用 WPF 的组合性质,可以像使用 DateScheduled 列一样对此列使用两个元素。 第一个元素是 TextBlock,用来显示值;第二个元素是 ComboBox,用于编辑目的。
  157.  
  158. 显示了同时使用这两个元素的方式。
  159.  
  160. 组合使用显示值的 TextBlock 和用于编辑的 ComboBox
  161.  
  162. <DataGridTemplateColumn x:Name="taskColumnFaster"
  163. Header="Task" Width="" >
  164. <DataGridTemplateColumn.CellTemplate>
  165. <DataTemplate>
  166. <TextBlock Text="{Binding Path=Task}" />
  167. </DataTemplate>
  168. </DataGridTemplateColumn.CellTemplate>
  169.  
  170. <DataGridTemplateColumn.CellEditingTemplate>
  171. <DataTemplate>
  172. <Grid FocusManager.FocusedElement=
  173. "{Binding ElementName= taskCombo}" >
  174. <ComboBox x:Name="taskCombo"
  175. ItemsSource="{Binding Source={StaticResource taskViewSource}}"
  176. SelectedItem ="{Binding Path=Task}"
  177. IsSynchronizedWithCurrentItem="False"/>
  178. </Grid>
  179. </DataTemplate>
  180. </DataGridTemplateColumn.CellEditingTemplate>
  181. </DataGridTemplateColumn>
  182.  
  183. TextBlock 与限制列表不存在依赖关系,因此能够显示数据库中存储的任何值。 不过,在编辑时就会用到 ComboBox,输入将限制为 frequencyViewSource 中的值。
  184.  
  185. 允许用户在单元格获得焦点时编辑 ComboBox
  186. 同样,因为 ComboBox 在用户在单元格中单击两次后方可使用,因此,请注意我将 ComboBox 封装在一个 Grid 中以利用 FocusManager
  187.  
  188. 考虑到用户可能通过单击 Task 单元格而不是移至第一列的方式开始新行数据输入,我修改了 SelectedCellsChanged 方法。 唯一的更改是代码还检查当前单元格是否位于 Task 列中:
  189.  
  190. private void scheduleItemsDataGrid_SelectedCellsChanged(object sender,
  191. System.Windows.Controls.SelectedCellsChangedEventArgs e)
  192. {
  193. if (e.AddedCells.Count == ) return;
  194. var currentCell = e.AddedCells[];
  195. string header = (string)currentCell.Column.Header;
  196.  
  197. if (currentCell.Column ==
  198. scheduleItemsDataGrid.Columns[DateScheduledColumnIndex]
  199. || currentCell.Column == scheduleItemsDataGrid.Columns[TaskColumnIndex])
  200. {
  201. scheduleItemsDataGrid.BeginEdit();
  202. }
  203. }

WPF中。。DataGrid 实现时间控件和下拉框控件的更多相关文章

  1. FineReport——JS二次开发(隐藏下拉框控件的倒三角)

    在对FR控件进行二次开发的过程中,需要自定义样式,比如下拉框控件带有自动检索的功能,但是又希望它的显示样式如同文本框一样,这时就需要隐藏多余的部分. 在对在线文档的查阅中可以发现很多选择器适用于多种控 ...

  2. DevExpress的下拉框控件ComboxBoxEdit怎样绑定键值对选项

    场景 DevExpress的下拉框控件ComboBoxEdit控件的使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1028 ...

  3. DevExpress的下拉框控件ComboBoxEdit控件的使用

    场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...

  4. DevExpress的下拉框控件LookUpEdit的使用、添加item选项值、修改默认显示值

    场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...

  5. 几种常用的控件(下拉框 可选框 起止日期 在HTML页面直接读取当前时间)

    下拉框 <div class="form-group">                        <label class="col-xs-3 c ...

  6. 用MVC的辅助方法自定义了两个控件:“可编辑的下拉框控件”和“文本框日历控件”

    接触MVC也没多长时间,一开始学的时候绝得MVC结构比较清晰.后来入了门具体操作下来感觉MVC控件怎么这么少还不可以像ASP.net form那样拖拽.这样设计界面来,想我种以前没学过JS,Jquer ...

  7. DropShadowEffect导致下拉框控件抖动

    <!--<Border.Effect> <DropShadowEffect Direction="180" BlurRadius="1" ...

  8. android 开发-spinner下拉框控件的实现

    Android提供实现下拉框功能的非常实用的控件Spinner. spinner控件需要向xml资源文件中添加spinner标签,如下: <Spinner android:id="@+ ...

  9. [原创]自己动手实现React-Native下拉框控件

    因项目需要,自己动手实现了一个下拉框组件,最近得空将控件独立出来开源上传到了Github和npm. Github地址(求Star 求Star 求Star 

随机推荐

  1. VS2013打开项目 提示Asp.net4.5未在web服务器上注册 F5运行 启动不来 权限

    打一个补丁 http://blogs.msdn.com/b/webdev/archive/2014/11/11/dialog-box-may-be-displayed-to-users-when-op ...

  2. iptables常用配置

    常用的iptables模板 #!/bin/sh iptables -F iptables -X iptables -F -t mangle iptables -t mangle -X iptables ...

  3. 使用Java语言开发机器学习框架和参数服务器

    https://github.com/wudikua/ps 本项目是我自己动手实现的机器学习训练框架,代码简单,有很多不完善,但是也保留了最小可用功能 通过自己编写这个项目,可以帮助自己入门机器学习 ...

  4. [转]solr系统query检索词特殊字符的处理

    原文地址:http://blog.csdn.net/wgw335363240/article/details/39889979 solr是基于 lucence开发的应用,如果query中带有非法字符串 ...

  5. 进入WinRe(windows恢复环境)

    放个预览图: 方法汇总: 1. 2 . +Shift  3 ”shutdown /r /o“ 或 "bootim" 4 5 启动中强制关闭3次以上 6 狂按F8 (不同的电脑操作不 ...

  6. [Python web开发] Web框架开发基础 (一)

    Python WEB框架 WSGI,WEB Server Gateway Interface,可以看做是一种底层协议,它规定了服务器程序和应用程序各自实现上面接口.Python的实现称为wsgiref ...

  7. sqoop2启动client异常

    java环境:  java version "10.0.1" ,启动sqoop-shell端或者是sqoop-client端异常,异常如下: [root@hadoop1 home] ...

  8. How RTT works

    13.2 How RTT works 13.2.1 Target implementation Real Time Terminal uses a SEGGER RTT Control Block s ...

  9. 为何.NET Core控制台项目发布后是一个dll文件,而不是exe文件?

    项目中有一个.NET Core控制台项目叫ConsoleCoreApp,写好代码后准备发布: 结果发布后生成的是一个dll文件...为不是一个exe的可执行文件: 后来了解到.NET Core的项目分 ...

  10. 前端css小米导航栏设置及盒子定位居中问题

    1.小米最上部导航栏设置 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...