【发布时间】:2011-07-29 06:49:16
【问题描述】:
我正在使用下面类图中的视图模型使用 DataGrid 进行时间表演示。
顶层类(ActivityCollectionViewModel)是网格的DataContext;它持有的活动集合(ActivityViewModel)是网格中的行项目。该活动有一个分配集合 (AllocationViewModel),它们是行项目 DataGrid 单元格(列)的大部分。
请注意,AllocationVm(单元格)有它自己的命令,MakeFullDayCommand。在当前的设计中,我在 AllocationVm 的父级和祖父级都有等效的命令。我这样做是因为我认为我可以绑定祖父母的命令,然后使用 collectionViewSource 的能力来维护选定的子虚拟机,以便始终调用正确的单元格命令。
实际上,跟踪很混乱,而且我无法单独绑定以保持所有内容同步,因此我在 DataGrid 中使用了一些代码,如下所示。
所以我想我会退后一步,看看是否有人可以提出比我所拥有的更简单更有效的设计,或者确认这是一个可行的解决方案并帮助我制定更好的数据绑定策略。
干杯,
浆果
工作原理
下面上下文菜单中的底部命令是我所指的嵌套命令。
代码隐藏
这段代码丑陋且难以测试!
/// <summary>
/// Synchronize the <see cref="ActivityViewModel.SelectedAllocationVm"/> here so the input binding
/// key (F8) is always working on the correct command.
/// </summary>
private void OnCurrentCellChanged(object sender, EventArgs e)
{
if (sender == null) return;
var grid = (DataGrid)sender;
if (grid.CurrentColumn == null) return;
var selectedActivity = (ActivityViewModel)grid.CurrentItem;
if (_isEditableDayOfTheWeekColumn(grid.CurrentColumn))
{
var dowCol = (DayOfTheWeekColumn)grid.CurrentColumn;
var index = Convert.ToInt32(dowCol.DowIndex);
selectedActivity.SetSelectedAllocationVm(index);
}
else
{
selectedActivity.SetSelectedAllocationVm(-1);
}
}
/// <summary>
/// Invoke the MakeFullDayCommand when the user double clicks an editable cell;
/// synchronize the selected allocation view model first.
/// </summary>
private void OnDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender == null) return;
var grid = (DataGrid)sender;
if (grid.CurrentColumn == null) return;
if (!_isEditableDayOfTheWeekColumn(grid.CurrentColumn)) return;
var selectedActivity = (ActivityViewModel) grid.CurrentItem;
var dowCol = (DayOfTheWeekColumn)grid.CurrentColumn;
var index = Convert.ToInt32(dowCol.DowIndex);
var allocationVm = selectedActivity.SetSelectedAllocationVm(index);
if (allocationVm.MakeFullDayCommand.CanExecute(null))
{
allocationVm.MakeFullDayCommand.Execute(null);
}
}
/// <summary>
/// Manipululate the context menu to show the correct description of the MakeFullDayCommand.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.Controls.ContextMenuEventArgs"/> instance containing the event data.</param>
void OnContextMenuOpening(object sender, ContextMenuEventArgs e) {
if (sender == null) return;
var grid = (DataGrid)sender;
if (grid.CurrentColumn == null) return;
const int INDEX_OF_MAKE_FULL_DAY_CMD = 1;
if (_isEditableDayOfTheWeekColumn(grid.CurrentColumn)) {
var selectedActivity = (ActivityViewModel) grid.CurrentItem;
var dowCol = (DayOfTheWeekColumn) grid.CurrentColumn;
var index = Convert.ToInt32(dowCol.DowIndex);
var allocationVm = selectedActivity.SetSelectedAllocationVm(index);
var menuItem = allocationVm.MakeFullDayCommand.ToMenuItem();
if (grid.ContextMenu.Items.Count == 1) {
Log.Info("{0}", allocationVm.MakeFullDayCommand.HeaderText);
grid.ContextMenu.Items.Add(menuItem);
}
else {
var currentItem = (MenuItem) grid.ContextMenu.Items.GetItemAt(INDEX_OF_MAKE_FULL_DAY_CMD);
if (currentItem.Command != menuItem.Command) {
// remove the outdated menu item before adding back the new one
grid.ContextMenu.Items.Remove(currentItem);
grid.ContextMenu.Items.Add(menuItem);
}
}
}
else
{
if (grid.ContextMenu.Items.Count == 2)
{
// we aren't on an editable cell - remove the command altogether
grid.ContextMenu.Items.RemoveAt(INDEX_OF_MAKE_FULL_DAY_CMD);
}
}
}
【问题讨论】:
标签: wpf silverlight data-binding mvvm