我有一个tabControl。在其中一个tabitem中我有一个usercontrol,它包含一个具有CanUserAddRows =“True”的数据网格。用户可以在列中键入数据并按下输入创建的新行(我假设datagrid执行此CanzserAddRows =“True”)。 问题是当我输入数据并更改标签时,我得到此异常“在'Addnew'开始的交易期间不允许使用”WPF datagrid'newitemplaceholderposition'“
有任何建议如何避免吗?
我试图将dg.CommitEdit()放在usercontrol.unloaded()上。我没有得到例外,但我没有得到新的一行。
答案 0 :(得分:3)
我遇到了同样的问题。找到两种可能的解决方法:
1 /触发DataGrid的CommitEdit事件,然后调用CommitEdit。我不确定为什么需要这最后一步,你可能不必在你的情况下调用CommitEdit。
DataGrid.CommitEditCommand.Execute(this.DataGridWorkItems, this.DataGridWorkItems);
yourDataGrid.CommitEdit(DataGridEditingUnit.Row, false);
2 /在键盘的“Return”键上模拟一个笔划:
var keyEventArgs = new KeyEventArgs(InputManager.Current.PrimaryKeyboardDevice,PresentationSource.FromDependencyObject(yourDataGrid), System.Environment.ProcessorCount, Key.Return);
keyEventArgs.RoutedEvent = UIElement.KeyDownEvent;
yourDataGrid.RaiseEvent(keyEventArgs);
我选择了最后一个解决方案,因为我对第一个解决方案产生了一些可疑的副作用。
答案 1 :(得分:3)
我遇到了同样的问题......这里有一些片段描述了我是如何解决它的。请注意,在我的情况下,我想拒绝更改以避免错误。如果您想提交更改,这可能会引导您朝着正确的方向前进。
1a)使用datagrid上的InitializingNewItem事件来捕获添加行。
private void mydatagrid_InitializingNewItem(object sender, InitializingNewItemEventArgs e)
{
_viewmodel.NewRowDefaults((DataRowView)e.NewItem);
}
1b)在这种情况下,我在视图模型中调用一个方法来填充行默认值并保存对该行的引用。
private DataRowView _drvAddingRow { get; set; }
public void NewRowDefaults(DataRowView drv)
{
_drvAddingRow = drv;
...
}
2)然后当您需要拒绝更改时(在通知属性更改或您的情况之前),请在捕获的数据视图上使用CancelEdit方法。
_drvAddingRow.CancelEdit();
答案 2 :(得分:1)
不幸的是,其他答案只能在某些情况下解决问题。例如,如果一个单元格在切换选项卡时出现验证错误,则其他解决方案将失败。
问题在于,更改IsEnabled时,CanUserAddRows会更改,并且会触发NewItemPlaceholderPosition重置。要解决此错误,我继承了DataGrid类,并向CanUserAddRowsProperty的CoerceValueCallback添加了一些逻辑。
namespace CustomControls
{
using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using Utilities;
public class FixedDataGrid : DataGrid
{
static FixedDataGrid()
{
var originalPropertyChangedCallback = CanUserAddRowsProperty.GetMetadata(typeof(DataGrid)).PropertyChangedCallback;
var originalCoerceValueCallback = CanUserAddRowsProperty.GetMetadata(typeof(DataGrid)).CoerceValueCallback;
CanUserAddRowsProperty.OverrideMetadata(typeof(FixedDataGrid), new FrameworkPropertyMetadata(true,
originalPropertyChangedCallback,
(d, e) =>
{
var ths = ((FixedDataGrid) d);
// Fixes System.InvalidOperationException: 'NewItemPlaceholderPosition' is not allowed during a transaction begun by 'AddNew'.
if (ths.IsEnabled) return originalCoerceValueCallback(d, e);
if (!((IEditableCollectionViewAddNewItem) ths.Items).CanAddNewItem &&
!((IEditableCollectionViewAddNewItem) ths.Items).CanCancelEdit)
return originalCoerceValueCallback(d, e);
ths.CancelEdit();
ReflectionUtils.InvokeMethod(ths, "CancelRowItem");
ReflectionUtils.InvokeMethod(ths, "UpdateNewItemPlaceholder", false);
ReflectionUtils.SetProperty(ths, "HasCellValidationError", false);
CommandManager.InvalidateRequerySuggested();
return originalCoerceValueCallback(d, e);
}));
}
}
}
namespace Utilities
{
using System;
using System.Reflection;
public class ReflectionUtils
{
public static void InvokeMethod(object obj, string name, params object[] args)
{
InvokeMethod(obj, obj.GetType(), name, args);
}
public static void InvokeMethod(object obj, Type type, string name, params object[] args)
{
var method = type.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
{
if (type.BaseType == null)
throw new MissingMethodException($"Couldn't find method {name} in {type}");
InvokeMethod(obj, type.BaseType, name, args);
return;
}
method.Invoke(obj, args);
}
public static T InvokeMethod<T>(object obj, string name, params object[] args)
{
return InvokeMethod<T>(obj, obj.GetType(), name, args);
}
public static T InvokeMethod<T>(object obj, Type type, string name, params object[] args)
{
var method = type.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
{
if (type.BaseType == null)
throw new MissingMethodException($"Couldn't find method {name} in {type}");
return InvokeMethod<T>(obj, type.BaseType, name, args);
}
return (T) method.Invoke(obj, args);
}
public static T GetProperty<T>(object obj, string name)
{
return GetProperty<T>(obj, obj.GetType(), name);
}
public static T GetProperty<T>(object obj, Type type, string name)
{
var prop = type
.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop == null)
{
if (type.BaseType == null)
throw new MissingMethodException($"Couldn't find property {name} in {type}");
return GetProperty<T>(obj, type.BaseType, name);
}
return (T) prop
.GetGetMethod(nonPublic: true).Invoke(obj, new object[] { });
}
public static void SetProperty<T>(object obj, string name, T val)
{
SetProperty(obj, obj.GetType(), name, val);
}
public static void SetProperty<T>(object obj, Type type, string name, T value)
{
var prop = type
.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop == null)
{
if (type.BaseType == null)
throw new MissingMethodException($"Couldn't find property {name} in {type}");
SetProperty(obj, type.BaseType, name, value);
return;
}
prop.GetSetMethod(nonPublic: true).Invoke(obj, new object[] {value});
}
}
}
此代码的工作方式是:更新IsEnabled时,CanUserAddRows会发生更改,并触发NewItemPlaceholderPosition的设置器。通过在设置NewItemPlaceholderPosition之前调用CancelRowItem和UpdateNewItemPlaceholder,我们可以立即取消交易(不足以调用CancelEdit)。将HasCellValidationError设置为false还可以帮助您从遇到验证错误时出现的一些极端情况中恢复过来。
答案 3 :(得分:0)
我使用过holmes的答案,但没有正确地为我工作。所以我改变了一点。
这是我的解决方案:
首先,由于我使用MVVM,我将此代码添加到datagrid:
<i:Interaction.Triggers>
<i:EventTrigger EventName="InitializingNewItem">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="OnDataGridInitializingNewItem"/>
</i:EventTrigger>
</i:Interaction.Triggers>
命名空间是:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
然后,我将此代码添加到ViewModel并设置DataGrid:
private DataGrid _dg { get; set; }
public void OnDataGridInitializingNewItem(object sender, InitializingNewItemEventArgs e)
{
if (_dg == null)
_dg = (DataGrid)sender;
}
毕竟,在需要的时候,我运行了这段代码:
_dg.CommitEdit();
最后它运作良好:)
PS: 首先,我尝试过CancelEdit方法而不是CommitEdit。它工作,我去了另一个像弹出窗口打开的视图。当我完成要做的事情并返回视图时,最后添加的行已经消失。但它致力于数据库。重新打开视图后,它就在那里。
答案 4 :(得分:0)
我遇到了这样的问题,但就我而言,网格被包裹在AdornerDecorator中,将其删除,一切正常