DataGridにバインドされたObservableCollectionを持っていますが、ユーザーがグリッドにデータを追加できるようにしますが、追加されたすべてのエントリの合計が100%。DataGrid内の新しい行の追加を取り消す
データグリッドにデータを受け入れるセルをフォーカスするには、DataGrid.RowEditEndingイベントを処理するコードを使用しています。トリッキーですが、それはある意味では機能します。
ここでは、合計100%のエントリがあります。 CollectionChangedイベントハンドラでは不要な追加をキャッチすることはできますが、もちろん、そこにいるとコレクションを変更することはできません。
誰かが望ましくない追加情報をキャッチして対処するための良い場所についての提案を受けましたか?
乾杯、
Berryl
ビューモデルのイベントハンドラコード
public ObservableCollection<RatioBagEntryVm> Ratios { get; private set; }
public RatioBagAllocatorVm() {
RatioBag = new RatioBag();
Ratios = new ObservableCollection<RatioBagEntryVm>();
Ratios.CollectionChanged += OnRatiosChanged;
}
private void OnRatiosChanged(object sender, NotifyCollectionChangedEventArgs e) {
SequencingService.Sequence(Ratios);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var entryVm in e.NewItems.Cast<RatioBagEntryVm>()) {
entryVm.PropertyChanged += OnRatioEntryChanged;
RatioBag.Add(entryVm.Ratio);
entryVm.Bag = RatioBag;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var entryVm in e.OldItems.Cast<RatioBagEntryVm>()) {
RatioBag.RemoveAt(entryVm.SequenceNumber - 1);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
コード(今の)ハンドラの後ろ
/// <summary>
/// Adapted from http://blogs.msdn.com/b/vinsibal/archive/2009/04/14/5-more-random-gotchas-with-the-wpf-datagrid.aspx
/// </summary>
private void OnDataGridRowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
var dg = sender as DataGrid;
if (e.EditAction != DataGridEditAction.Commit) return;
//
// custom commit action:
// moves to the next row and opens the second cell for edit
// if the next row is the NewItemPlaceholder
//
var wasLastRowInGrid = e.Row.Item == dg.Items[dg.Items.Count - 2];
if (!wasLastRowInGrid) return;
if (dg.HasError()) return;
// set the new cell to be the last row and the second column
const int colIndex = 1;
var rowToSelect = dg.Items[dg.Items.Count - 1];
var colToSelect = dg.Columns[colIndex];
var rowIndex = dg.Items.IndexOf(rowToSelect);
switch (dg.SelectionUnit)
{
case DataGridSelectionUnit.Cell:
case DataGridSelectionUnit.CellOrRowHeader:
// select the new cell
dg.SelectedCells.Clear();
dg.SelectedCells.Add(new DataGridCellInfo(rowToSelect, colToSelect));
break;
case DataGridSelectionUnit.FullRow:
e.Row.IsSelected = true;
break;
default:
throw new ArgumentOutOfRangeException();
}
// this is the extra tricky part
Dispatcher.BeginInvoke(new DispatcherOperationCallback(param =>
{
// get the new cell, set focus, then open for edit
var cell = dg.GetCell(rowIndex, colIndex);
cell.Focus();
dg.BeginEdit();
return null;
}), DispatcherPriority.Background, new object[] { null });
}
}
SOLUTION
元のコードのトリッキーな部分Dispatcherを使ってwhを模倣していたDataGrid.RowEndedEventで利用できるようにしたい場合は、idea私のコードに基づいて書いたVincent Sibalのとおりです。
これもキャンセルする場所であり、変更されたコードは以下のとおりです。このようにビューモデルにアクセスすることは、MVVMダイジェストで読むことはほとんど不可能であり、確かにハックのハックですが、それは動作します。
// this is the extra tricky part
Dispatcher.BeginInvoke(new DispatcherOperationCallback(param =>
{
// get the new cell, set focus, then open for edit
var cell = dg.GetCell(rowIndex, colIndex);
cell.Focus();
// cancel the row commit if we are already fully allocated
var win = dg.FindVisualParent<Window>();
var vm = win.DataContext as RatioBagAllocatorVm;
if(vm.RatioBag.IsAllocatable)
e.Cancel = true;
else {
dg.BeginEdit();
}
return null;
}), DispatcherPriority.Background, new object[] { null });
@ianscol。ええ、私はむしろ追加を防止するだろうが、私はそれを行うことができるか分からない! DataGridがトリガしています... – Berryl
'OnDataGridRowEditEnding'に' DataGridRowEditEndingEventArgs.Cancel = true'を設定できますか?イベントの比率にアクセスできるように設定すれば、新しい比率を計算することができるので、 'Cancel = true'で行をロールバックできます。私は上記のコードを吐き出す前に、まずそれを考えていたはずです! – ianschol
butt醜いが、butt uglyよりもうまくいかない!私がしたことのための変更されたポストの終わりを見てください。乾杯 – Berryl