WPF中。。DataGrid 实现时间控件和下拉框控件
- DatePicker 和新的 DataGrid 行
- 用户与 DataGrid 中日期列的交互给我造成了很大的麻烦。 我通过将一个 Data Source 对象拖动到 WPF 窗口上,创建了一个 DataGrid。 设计器的默认行为是为该对象中的每个 DateTime 值创建一个 DatePicker。 例如,下面是为一个 DateScheduled 字段创建的列:
- <DataGridTemplateColumn x:Name=" dateScheduledColumn"
- Header="DateScheduled" Width="">
- <DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <DatePicker
- SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
- ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
- </DataTemplate>
- </DataGridTemplateColumn.CellTemplate>
- </DataGridTemplateColumn>
- 这一默认行为对编辑造成不便。 编辑时现有行不会更新。 DatePicker 不会在 DataGrid 中触发编辑,这表示数据绑定功能不会将所做的更改推送至基础对象。 通过向 Binding 元素添加 UpdateSourceTrigger 属性并将属性值设置为 PropertyChanged,可以解决这个特定的问题:
- <DatePicker
- SelectedDate="{Binding Path= DateScheduled, Mode=TwoWay,
- ValidatesOnExceptions=true, NotifyOnValidationError=true,
- UpdateSourceTrigger=PropertyChanged}" />
- 不过,添加这些新行后,DatePicker 不能触发 DataGrid 编辑模式的问题变得更加严重。 在 DataGrid 中,新行由 NewRowPlaceHolder 表示。 首次编辑新行中的单元格时,编辑模式会在数据源中触发插入(再次说明,不是在数据库中,而是在内存中的基础源中)。 因为 DatePicker 不触发编辑模式,所以这不会发生。
- 因为我的行中的日期列恰好是第一列,所以我发现了这个问题。 我本来想使用它来触发该行的编辑模式的。
- 图 所示为一个新行,在其中的第一个可编辑列中输入了日期。
- 图 在新行占位符中输入日期值
- 但在编辑下一列中的值之后,前一编辑值丢失,如图 所示。
- 图 修改新行中 Task 列值之后日期值丢失
- 第一列中的键值变为 ,刚刚输入的日期值变为 //。 编辑 Task 列最终会使 DataGrid 在数据源中添加一个新实体。 ID 值变为整数(默认值 ),日期值变为 .NET 默认的最小日期 //。 如果我为此类指定过默认日期,则用户输入的日期将变为此类的默认日期,而不是 .NET 的默认日期。 请注意,Date Performed 列中的日期没有更改为其默认值。 这是因为 DatePerformed 是可以为 Null 的属性。
- 那么,现在用户是不是必须回去重新修复 Scheduled Date? 我相信用户肯定不愿意这样做。 这个问题困扰了我一段时间。 我甚至曾将该列改成 DataTextBoxColumn,但之后我必须处理 DatePicker 起保护作用的验证问题。
- 最后,WPF 团队的 Varsha Mahadevanset 给我指出了正确的道路。
- 通过利用 WPF 的组合性质,可以对此列使用两个元素。 DataGridTemplateColumn 不仅有 CellTemplate 元素,还有 CellEditingTemplate。 我没有要求 DatePicker 控件触发编辑模式,而只在已经编辑时使用 DatePicker。 为了在 CellTemplate 中显示日期,我切换到了 TextBlock。 下面是 dateScheduledCoumn 的新 XAML:
- <DataGridTemplateColumn x:Name="dateScheduledColumn"
- Header="Date Scheduled" Width="">
- <DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <TextBlock Text="{Binding Path= DateScheduled, StringFormat=\{0:d\}}" />
- </DataTemplate>
- </DataGridTemplateColumn.CellTemplate>
- <DataGridTemplateColumn.CellEditingTemplate>
- <DataTemplate>
- <DatePicker SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
- ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
- </DataTemplate>
- </DataGridTemplateColumn.CellEditingTemplate>
- </DataGridTemplateColumn>
- 请注意,我不再需要指定 UpdateSourceTrigger。 我对 DatePerformed 列也进行了同样的更改。
- 现在,这些日期列一开始是简单文本,在您进入该单元格后才切换到 DatePicker,如图 所示。
- 图 DateScheduled 列同时使用 TextBlock 和 DatePicker
- 在新行上面的行中没有 DatePicker 日历图标。
- 但这还是有点不对。 开始编辑这一行时仍然会得到默认的 .NET 值。 这时,您就可以从在基础类中定义默认值受益。 我修改了 ScheduleItem 类的构造函数,使之将新对象初始化为当天日期。 如果从数据库检索到数据,它将覆盖该默认值。 我的项目使用了实体框架,因此类会自动生成。 不过,生成的类是分部类,这样,我就可以将此构造函数添加到附加的分部类中:
- public partial class ScheduleItem
- {
- public ScheduleItem()
- {
- DateScheduled = DateTime.Today;
- }
- }
- 现在,当我通过修改 DateScheduled 列开始在新行占位符中输入数据时,DataGrid 会为我创建一个新的 ScheduleItem,并且在 DatePicker 控件中显示默认值(当天日期)。 现在,当用户继续编辑此行时,输入的值会继续有效。
- 减少用户在编辑时需要点击的次数
- 两部分模板的一个弊端是必须点击单元格两次才能触发 DatePicker。 这会对数据输入人员造成不便,特别是对那些习惯于使用键盘输入数据而不使用鼠标的人员。 因为 DatePicker 位于编辑模板中,所以除非触发编辑模式,否则它不会获得焦点(这是默认行为)。 这是针对 TextBox 进行的设计,很适合 TextBox 使用。 但这种设计不太适用于 DatePicker。 可以结合使用 XAML 和代码来强制 DatePicker 在用户切换到该单元格时准备好键入。
- 首先,需要在 CellEditingTemplate 中添加一个 Grid 容器,使它成为 DatePicker 的容器。 然后,可以使用 WPF FocusManager 强制此 Grid 在用户进入该单元格时成为单元格焦点。 下面是作为 DatePicker 容器的新 Grid 元素:
- <Grid FocusManager.FocusedElement="{Binding ElementName= dateScheduledPicker}">
- <DatePicker x:Name=" dateScheduledPicker"
- SelectedDate="{Binding Path=DateScheduled, Mode=TwoWay,
- ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
- </Grid>
- 请注意,我为 DatePicker 控件提供了一个名称,并使用 FocusedElement Binding ElementName 指向了该名称。
- 现在请将注意力转到包含此 Date-Picker 的 DataGrid,注意,我添加了三个新属性(RowDetailsVisibilityMode、SelectionMode 和 SelectionUnit)和一个新的事件处理程序 (SelectedCellsChanged):
- <DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
- ItemsSource="{Binding}" Margin="12,12,22,31"
- Name="scheduleItemsDataGrid"
- RowDetailsVisibilityMode="VisibleWhenSelected"
- SelectionMode="Extended" SelectionUnit="Cell"
- SelectedCellsChanged="scheduleItemsDataGrid_SelectedCellsChanged">
- 对 DataGrid 进行的更改会启用当用户选择该 DataGrid 中的新单元格进行通知的功能。 最后,需要确保当用户执行此操作时 DataGrid 确实进入编辑模式,这会在 DatePicker 中向用户提供必要的光标。 scheduleItemsDataGrid_SelectedCellsChanged 方法将提供这最后一部分逻辑:
- private void scheduleItemsDataGrid_SelectedCellsChanged
- (object sender,
- System.Windows.Controls.SelectedCellsChangedEventArgs e)
- {
- if (e.AddedCells.Count == ) return;
- var currentCell = e.AddedCells[];
- string header = (string)currentCell.Column.Header;
- var currentCell = e.AddedCells[];
- if (currentCell.Column ==
- scheduleItemsDataGrid.Columns[DateScheduledColumnIndex])
- {
- scheduleItemsDataGrid.BeginEdit();
- }
- }
- 请注意,在类声明中,我将常量 DateScheduledColumnIndex 定义为 ,即该列在网格中的位置。
- 完成这些更改后,最终用户会很满意。 我费了很大心思才找出使 DatePicker 在 DataGrid 内出色工作的正确 XAML 和代码元素组合,希望这可以帮助您避免经历同样的困难。 现在,UI 以用户熟悉的方式工作了。
- 使受限 ComboBox 显示旧值
- 获取在 DataGridTemplateColumn 中对元素分层的价值之后,我再次考虑了另一个我几乎已经放弃的 DataGrid-ComboBox 列相关问题。
- 编写这一特定应用程序的目的是为了用旧数据替换旧应用程序。 旧应用程序允许用户不经太多控制输入数据。 在新应用程序中,客户端要求通过下拉列表对一些数据输入进行限制。 通过使用字符串集合很容易提供下拉列表的内容。 难点在于仍要显示旧数据,即使此数据不包含在新的限制列表中也是如此。
- 我首先尝试使用 DataGridComboBoxColumn:
- <DataGridComboBoxColumn x:Name="frequencyCombo"
- MinWidth="" Header="Frequency"
- ItemsSource="{Binding Source={StaticResource frequencyViewSource}}"
- SelectedValueBinding=
- "{Binding Path=Frequency, UpdateSourceTrigger=PropertyChanged}">
- </DataGridComboBoxColumn>
- 在代码隐藏文件中定义源项:
- private void PopulateTrueFrequencyList()
- {
- _frequencyList =
- new List<String>{"",
- "Initial","2 Weeks",
- "1 Month", "2 Months",
- "3 Months", "4 Months",
- "5 Months", "6 Months",
- "7 Months", "8 Months",
- "9 Months", "10 Months",
- "11 Months", "12 Months"
- };
- }
- 此 _frequencyList 绑定到另一方法中的 frequencyViewSource.Source。
- 在无数种可能的 DataGridCombo-BoxColumn 配置中,我找不到任何办法来显示可能已经存储在数据库表的 Frequency 字段中的不同值。 我就不一一列举我试过的所有解决方法了,其中一个是将这些额外的值动态添加到 _frequencyList 底部,然后根据需要删除它们。 我并不喜欢这个解决方法,但恐怕我不得不接受它。
- 我知道编写 UI 的 WPF 分层方法必须为此提供一种机制,并且已经解决了 Date-Picker 问题,因此我意识到可以对 ComboBox 使用相似的方法。 这个技巧的第一部分是避免使用华而不实的 DataGridComboBoxColumn,而是使用更经典的将 ComboBox 嵌入 DataGridTemplateColumn 内部的方法。 然后,利用 WPF 的组合性质,可以像使用 DateScheduled 列一样对此列使用两个元素。 第一个元素是 TextBlock,用来显示值;第二个元素是 ComboBox,用于编辑目的。
- 图 显示了同时使用这两个元素的方式。
- 图 组合使用显示值的 TextBlock 和用于编辑的 ComboBox
- <DataGridTemplateColumn x:Name="taskColumnFaster"
- Header="Task" Width="" >
- <DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <TextBlock Text="{Binding Path=Task}" />
- </DataTemplate>
- </DataGridTemplateColumn.CellTemplate>
- <DataGridTemplateColumn.CellEditingTemplate>
- <DataTemplate>
- <Grid FocusManager.FocusedElement=
- "{Binding ElementName= taskCombo}" >
- <ComboBox x:Name="taskCombo"
- ItemsSource="{Binding Source={StaticResource taskViewSource}}"
- SelectedItem ="{Binding Path=Task}"
- IsSynchronizedWithCurrentItem="False"/>
- </Grid>
- </DataTemplate>
- </DataGridTemplateColumn.CellEditingTemplate>
- </DataGridTemplateColumn>
- TextBlock 与限制列表不存在依赖关系,因此能够显示数据库中存储的任何值。 不过,在编辑时就会用到 ComboBox,输入将限制为 frequencyViewSource 中的值。
- 允许用户在单元格获得焦点时编辑 ComboBox
- 同样,因为 ComboBox 在用户在单元格中单击两次后方可使用,因此,请注意我将 ComboBox 封装在一个 Grid 中以利用 FocusManager。
- 考虑到用户可能通过单击 Task 单元格而不是移至第一列的方式开始新行数据输入,我修改了 SelectedCellsChanged 方法。 唯一的更改是代码还检查当前单元格是否位于 Task 列中:
- private void scheduleItemsDataGrid_SelectedCellsChanged(object sender,
- System.Windows.Controls.SelectedCellsChangedEventArgs e)
- {
- if (e.AddedCells.Count == ) return;
- var currentCell = e.AddedCells[];
- string header = (string)currentCell.Column.Header;
- if (currentCell.Column ==
- scheduleItemsDataGrid.Columns[DateScheduledColumnIndex]
- || currentCell.Column == scheduleItemsDataGrid.Columns[TaskColumnIndex])
- {
- scheduleItemsDataGrid.BeginEdit();
- }
- }
WPF中。。DataGrid 实现时间控件和下拉框控件的更多相关文章
- FineReport——JS二次开发(隐藏下拉框控件的倒三角)
在对FR控件进行二次开发的过程中,需要自定义样式,比如下拉框控件带有自动检索的功能,但是又希望它的显示样式如同文本框一样,这时就需要隐藏多余的部分. 在对在线文档的查阅中可以发现很多选择器适用于多种控 ...
- DevExpress的下拉框控件ComboxBoxEdit怎样绑定键值对选项
场景 DevExpress的下拉框控件ComboBoxEdit控件的使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1028 ...
- DevExpress的下拉框控件ComboBoxEdit控件的使用
场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...
- DevExpress的下拉框控件LookUpEdit的使用、添加item选项值、修改默认显示值
场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...
- 几种常用的控件(下拉框 可选框 起止日期 在HTML页面直接读取当前时间)
下拉框 <div class="form-group"> <label class="col-xs-3 c ...
- 用MVC的辅助方法自定义了两个控件:“可编辑的下拉框控件”和“文本框日历控件”
接触MVC也没多长时间,一开始学的时候绝得MVC结构比较清晰.后来入了门具体操作下来感觉MVC控件怎么这么少还不可以像ASP.net form那样拖拽.这样设计界面来,想我种以前没学过JS,Jquer ...
- DropShadowEffect导致下拉框控件抖动
<!--<Border.Effect> <DropShadowEffect Direction="180" BlurRadius="1" ...
- android 开发-spinner下拉框控件的实现
Android提供实现下拉框功能的非常实用的控件Spinner. spinner控件需要向xml资源文件中添加spinner标签,如下: <Spinner android:id="@+ ...
- [原创]自己动手实现React-Native下拉框控件
因项目需要,自己动手实现了一个下拉框组件,最近得空将控件独立出来开源上传到了Github和npm. Github地址(求Star 求Star 求Star
随机推荐
- 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 ...
- iptables常用配置
常用的iptables模板 #!/bin/sh iptables -F iptables -X iptables -F -t mangle iptables -t mangle -X iptables ...
- 使用Java语言开发机器学习框架和参数服务器
https://github.com/wudikua/ps 本项目是我自己动手实现的机器学习训练框架,代码简单,有很多不完善,但是也保留了最小可用功能 通过自己编写这个项目,可以帮助自己入门机器学习 ...
- [转]solr系统query检索词特殊字符的处理
原文地址:http://blog.csdn.net/wgw335363240/article/details/39889979 solr是基于 lucence开发的应用,如果query中带有非法字符串 ...
- 进入WinRe(windows恢复环境)
放个预览图: 方法汇总: 1. 2 . +Shift 3 ”shutdown /r /o“ 或 "bootim" 4 5 启动中强制关闭3次以上 6 狂按F8 (不同的电脑操作不 ...
- [Python web开发] Web框架开发基础 (一)
Python WEB框架 WSGI,WEB Server Gateway Interface,可以看做是一种底层协议,它规定了服务器程序和应用程序各自实现上面接口.Python的实现称为wsgiref ...
- sqoop2启动client异常
java环境: java version "10.0.1" ,启动sqoop-shell端或者是sqoop-client端异常,异常如下: [root@hadoop1 home] ...
- How RTT works
13.2 How RTT works 13.2.1 Target implementation Real Time Terminal uses a SEGGER RTT Control Block s ...
- 为何.NET Core控制台项目发布后是一个dll文件,而不是exe文件?
项目中有一个.NET Core控制台项目叫ConsoleCoreApp,写好代码后准备发布: 结果发布后生成的是一个dll文件...为不是一个exe的可执行文件: 后来了解到.NET Core的项目分 ...
- 前端css小米导航栏设置及盒子定位居中问题
1.小米最上部导航栏设置 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...