/// <summary>
/// This class help to create data grid cell which only support interger numbers.
/// </summary>
public class DataGridNumericColumn : DataGridTextColumn
{
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
TextBox edit = editingElement as TextBox;
if (edit != null) edit.PreviewTextInput += OnPreviewTextInput;
return base.PrepareCellForEdit(editingElement, editingEventArgs);
}
private void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
int value;
if (!int.TryParse(e.Text, out value))
e.Handled = true;
}
}
public class DataGridNumberColumn : DataGridTextColumn
{
private TextBoxInputBehavior _behavior;
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var element = base.GenerateElement(cell, dataItem);
// A clever workaround the StringFormat issue with the Binding set to the 'Binding' property. If you use StringFormat it
// will only work in edit mode if you changed the value, otherwise it will retain formatting when you enter editing.
if (!string.IsNullOrEmpty(StringFormat))
{
BindingOperations.ClearBinding(element, TextBlock.TextProperty);
BindingOperations.SetBinding(element, FrameworkElement.TagProperty, Binding);
BindingOperations.SetBinding(element,
TextBlock.TextProperty,
new Binding
{
Source = element,
Path = new PropertyPath("Tag"),
StringFormat = StringFormat
});
}
return element;
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
if (!(editingElement is TextBox textBox))
return null;
var originalText = textBox.Text;
_behavior = new TextBoxInputBehavior
{
IsNumeric = true,
EmptyValue = EmptyValue,
IsInteger = IsInteger
};
_behavior.Attach(textBox);
textBox.Focus();
if (editingEventArgs is TextCompositionEventArgs compositionArgs) // User has activated editing by already typing something
{
if (compositionArgs.Text == "\b") // Backspace, it should 'clear' the cell
{
textBox.Text = EmptyValue;
textBox.SelectAll();
return originalText;
}
if (_behavior.ValidateText(compositionArgs.Text))
{
textBox.Text = compositionArgs.Text;
textBox.Select(textBox.Text.Length, 0);
return originalText;
}
}
if (!(editingEventArgs is MouseButtonEventArgs) || !PlaceCaretOnTextBox(textBox, Mouse.GetPosition(textBox)))
textBox.SelectAll();
return originalText;
}
private static bool PlaceCaretOnTextBox(TextBox textBox, Point position)
{
int characterIndexFromPoint = textBox.GetCharacterIndexFromPoint(position, false);
if (characterIndexFromPoint < 0)
return false;
textBox.Select(characterIndexFromPoint, 0);
return true;
}
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
UnwireTextBox();
base.CancelCellEdit(editingElement, uneditedValue);
}
protected override bool CommitCellEdit(FrameworkElement editingElement)
{
UnwireTextBox();
return base.CommitCellEdit(editingElement);
}
private void UnwireTextBox() => _behavior.Detach();
public static readonly DependencyProperty EmptyValueProperty = DependencyProperty.Register(
nameof(EmptyValue),
typeof(string),
typeof(DataGridNumberColumn));
public string EmptyValue
{
get => (string)GetValue(EmptyValueProperty);
set => SetValue(EmptyValueProperty, value);
}
public static readonly DependencyProperty IsIntegerProperty = DependencyProperty.Register(
nameof(IsInteger),
typeof(bool),
typeof(DataGridNumberColumn));
public bool IsInteger
{
get => (bool)GetValue(IsIntegerProperty);
set => SetValue(IsIntegerProperty, value);
}
public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register(
nameof(StringFormat),
typeof(string),
typeof(DataGridNumberColumn));
public string StringFormat
{
get => (string) GetValue(StringFormatProperty);
set => SetValue(StringFormatProperty, value);
}
}
8条答案
按热度按时间kcrjzv8t1#
基于@nit的建议,你可以创建自己的
DataGridTextColumn
派生类,如下所示:在PrepareCellForEdit方法中,将
OnPreviewTextInput
方法注册到编辑TextBox
PreviewTextInput事件,在该事件中验证数值。在xaml中,您只需使用它:
希望这个能帮上忙
a0zr77ik2#
使用
TryParse
代替,这有助于将输入值限制为整数。slsn1g293#
如果你不想显示任何验证错误,只想阻止任何非数字值,那么你可以创建
DataGridTemplateColumn
,并在CellEditingTemplate
中使用TextBox
。在TextBox的
PreviewTextInput
中,如果值不是整数,则设置e.Handled = true
:jq6vz3qz4#
我来这里是为了解决同样的问题:将
DataGrid
上单元格的输入约束为数字。但这个公认的答案对我不起作用。以下机构做到了这一点:1.为
DataGrid
添加PreparingForCellEdit
的事件处理程序。1.在该事件处理程序中,将
EditingElement
强制转换为TextBox
,并将PreviewTextInput
的事件处理程序添加到TextBox
。1.在
PreviewTextInput
事件处理程序中,如果不允许输入,则将e.Handled
设置为true。如果用户单击要编辑的单元格,则上述步骤有效。但是,如果单元格未处于编辑模式,则不会调用
PreparingForCellEdit
事件。要在这种情况下执行验证,请执行以下操作:1.为
PreviewTextInput
的DataGrid
添加事件处理程序。1.在该事件处理程序中,安全地将
e.OriginalSource
转换为DataGridCell
(如果不是DataGridCell
,则退出),检查DataGridCell's
IsEditing
属性,如果单元格未编辑,则将e.Handled
设置为true。上面的效果是,用户必须单击单元格才能编辑其内容,因此,对单元格内容的所有更改都将调用上面的
PreparingForCellEdit
/PreviewTextInput
组合。flvlnr445#
只是为了扩展@Omribitan的答案,以下是添加了数据
Paste
防护的解决方案:7ivaypg96#
不管怎样,我是这么解决的。此解决方案允许您在验证输入时指定各种选项,允许使用字符串格式(例如数据网格中的“$15.00”)和更多。
Binding
类本身提供的空值和字符串格式不足以满足需要,因为当单元格可编辑时,这两种格式都不能正确工作,因此这个类涵盖了它。它使用了另一个我已经用了很久的类:TextBoxInputBehavior
,它对我来说是一笔无价的财富,它最初来自WPF – TextBox Input Behavior博客文章,尽管这里的版本似乎要老得多(但经过了很好的测试)。因此,我所做的只是将我在TextBox上已经拥有的现有功能转移到my custom列,因此我在两者中具有相同的行为。是不是很棒?下面是自定义列的代码:
我所做的是偷看
DataGridTextColumn
的源代码,并以几乎相同的方式处理TextBox创建,并将自定义行为附加到TextBox。下面是我附加的行为的代码(这是一个可以在任何TextBox上使用的行为):
以上行为课的所有好成绩都归功于blindmeis,我只是随着时间的推移调整了一下。在检查他的博客后,我看到他有一个更新的版本,所以你可以看看。我很高兴地发现我也可以在DataGrid上使用他的行为!
这个解决方案工作得很好,你可以通过鼠标/键盘正确地编辑单元格,正确地粘贴内容,使用任何绑定源更新触发器,使用任何字符串格式等。- 它只是工作。
下面是一个如何使用它的示例:
希望这对某人有帮助。
2w2cym1i7#
我继续从Omris方法,但我希望能够删除单元格值后,它已输入的情况下,他们想清除它
我这样做的方法是覆盖CommitCellEdit方法并使字符串为null而不是空白。我也用decimal?在我的情况下
kxe2p93d8#
这个类扩展了前面的答案的功能,而不会像后面的一些答案那样变得过于复杂。
主要增加的内容是:
*TextBox_Loaded用于处理用户直接在单元格上输入而不是首先进入编辑模式的情况
*TextBox_LostFocus清理用户输入。处理小数点后的前导0和尾随0等。
其余的与前面的答案非常相似,除了这个检查数字输入是否与Regex有效(允许负数和小数)。