WPF,Datagrid 自定义 DataGridTextColumn DependencyProperty 不工作
WPF, Datagrid Custom DataGridTextColumn DependencyProperty not working
我有以下习惯 Datagrid
:
<ZF:ZFDataGrid
x:Name="dgvGrid"
HorizontalAlignment="Stretch" VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CanUserAddRows="True"
CanUserDeleteRows="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
CanUserSortColumns="False"
IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
SelectionMode="Single"
ItemsSource="{Binding POSModel}">
<ZF:DataGridNumericColumn
Header="Qty"
Width="80"
AllowDecimalSign="{Binding Path=IsUseDecimal}"/>
</ZF:ZFDataGrid>
我用过MVVM模式。
IsUseDecimal
是一个 boolean
属性。
而且,我创建了 DependencyProperty
名称 AllowDecimalSign
。如果我更改 IsUseDecimal
的值,那么我希望 AllowDecimalSign
也成为该值。但是,它不起作用。
public class DataGridNumericColumn : DataGridTextColumn
{
private static readonly Regex NonnumericChars = new Regex(@"\D");
private static readonly Regex NonnumericCharsExceptFirstMinus =
new Regex(@"(?<!^[^-]*)-|[^\d-]");
public static readonly DependencyProperty AllowDecimalSignProperty =
DependencyProperty.Register(
"AllowDecimalSign",
typeof(bool),
typeof(DataGridNumericColumn),
new PropertyMetadata(false, new PropertyChangedCallback(ValueChangedCallBack)));
public static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
}
public bool AllowDecimalSign
{
get { return (bool)GetValue(AllowDecimalSignProperty); }
set { SetValue(AllowDecimalSignProperty, value); }
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
var textBox = (TextBox) editingElement;
textBox.PreviewTextInput += OnPreviewTextInput;
textBox.PreviewLostKeyboardFocus += OnPreviewLostKeyboardFocus;
DataObject.AddPastingHandler(textBox, this.OnPaste);
return base.PrepareCellForEdit(editingElement, editingEventArgs);
}
private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
var textBox = (TextBox)sender;
///WHY this.AllowDecimalSign always False ???
if (this.AllowDecimalSign && e.Text == "." && textBox.Text.Contains("."))
e.Handled = true;
if (this.AllowDecimalSign && e.Text == ".")
return;
if (!this.IsNumeric(e.Text))
e.Handled = true;
}
private void OnPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var textBox = (TextBox) sender;
textBox.Text = this.ExtractNumericParts(textBox.Text);
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
if(!e.SourceDataObject.GetDataPresent(DataFormats.Text, true))
return;
var textBox = (TextBox)sender;
var preSelection = textBox.Text.Substring(0, textBox.SelectionStart);
var postSelection = textBox.Text.Substring(textBox.SelectionStart
+ textBox.SelectionLength);
var pastedText = (string)e.SourceDataObject.GetData(DataFormats.Text);
if (!this.IsNumeric(preSelection + pastedText + postSelection))
e.CancelCommand();
}
private bool IsNumeric(string text)
{
var result = false;
if(AllowDecimalSign)
{
decimal number;
result = decimal.TryParse(text, out number);
if (!this.AllowNegativeValues)
return result && number >= 0;
}
else
{
int number;
result = Int32.TryParse(text, out number);
if (!this.AllowNegativeValues)
return result && number >= 0;
}
return result;
}
private string ExtractNumericParts(string text)
{
if (this.IsNumeric(text))
return text;
text = this.RemoveIllegalChars(text);
return this.TrimDigitsToInt32Range(text);
}
private string RemoveIllegalChars(string text)
{
var illegalChars = this.AllowNegativeValues
? NonnumericCharsExceptFirstMinus
: NonnumericChars;
return illegalChars.Replace(text, string.Empty);
}
private string TrimDigitsToInt32Range(string numericText)
{
if (string.IsNullOrEmpty(numericText))
return "0";
return this.IsNumeric(numericText)
? numericText
: this.TrimDigitsToInt32Range(
numericText.Remove(numericText.Length - 1));
}
}
AllowDecimalSign
的值始终是 false
并且不反映 IsUseDecimal
的值,即使我也使用了此代码:
AllowDecimalSign="{Binding Path=IsUseDecimal, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
恐怕绑定不适用于任何类型的 DataGridColumns。它们没有 DataContext,也不是可视化树的一部分。
要使列中的绑定起作用,您必须借助代理项来设置 DataContext 或其他类似的解决方法。
,对于 VisualBrush
class 在这种情况下,但对于 DataGridColumn
.
应该同样有效
我假设 IsUseDecimal
是您的 ViewModel(或 DataGrid 具有的任何 DataContext)中的 属性。
代理元素:
public class DataContextProxy: Freezable
{
public DataContextProxy()
{
BindingOperations.SetBinding(this, DataContextProperty, new Binding());
}
public object DataContext
{
get { return GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
public static readonly DependencyProperty DataContextProperty = FrameworkElement
.DataContextProperty.AddOwner(typeof (DataContextProxy));
protected override Freezable CreateInstanceCore()
{
return new DataContextProxy();
}
}
并将其添加到资源中并在您的专栏中使用它:
<ZF:ZFDataGrid
x:Name="dgvGrid"
HorizontalAlignment="Stretch" VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CanUserAddRows="True"
CanUserDeleteRows="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
CanUserSortColumns="False"
IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
SelectionMode="Single"
ItemsSource="{Binding POSModel}">
<ZF:ZFDataGrid.Resources>
<behavior:DataContextProxy x:Key="Proxy"
DataContext="{Binding}" />
</ZF:ZFDataGrid.Resources>
<ZF:ZFDataGrid.Columns>
<ZF:DataGridNumericColumn
Header="Qty"
Width="80"
AllowDecimalSign="{Binding Path=DataContext.IsUseDecimal,
Source={StaticResource Proxy}}"/>
</ZF:ZFDataGrid.Columns>
</ZF:ZFDataGrid>
我有以下习惯 Datagrid
:
<ZF:ZFDataGrid
x:Name="dgvGrid"
HorizontalAlignment="Stretch" VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CanUserAddRows="True"
CanUserDeleteRows="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
CanUserSortColumns="False"
IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
SelectionMode="Single"
ItemsSource="{Binding POSModel}">
<ZF:DataGridNumericColumn
Header="Qty"
Width="80"
AllowDecimalSign="{Binding Path=IsUseDecimal}"/>
</ZF:ZFDataGrid>
我用过MVVM模式。
IsUseDecimal
是一个 boolean
属性。
而且,我创建了 DependencyProperty
名称 AllowDecimalSign
。如果我更改 IsUseDecimal
的值,那么我希望 AllowDecimalSign
也成为该值。但是,它不起作用。
public class DataGridNumericColumn : DataGridTextColumn
{
private static readonly Regex NonnumericChars = new Regex(@"\D");
private static readonly Regex NonnumericCharsExceptFirstMinus =
new Regex(@"(?<!^[^-]*)-|[^\d-]");
public static readonly DependencyProperty AllowDecimalSignProperty =
DependencyProperty.Register(
"AllowDecimalSign",
typeof(bool),
typeof(DataGridNumericColumn),
new PropertyMetadata(false, new PropertyChangedCallback(ValueChangedCallBack)));
public static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
}
public bool AllowDecimalSign
{
get { return (bool)GetValue(AllowDecimalSignProperty); }
set { SetValue(AllowDecimalSignProperty, value); }
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
var textBox = (TextBox) editingElement;
textBox.PreviewTextInput += OnPreviewTextInput;
textBox.PreviewLostKeyboardFocus += OnPreviewLostKeyboardFocus;
DataObject.AddPastingHandler(textBox, this.OnPaste);
return base.PrepareCellForEdit(editingElement, editingEventArgs);
}
private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
var textBox = (TextBox)sender;
///WHY this.AllowDecimalSign always False ???
if (this.AllowDecimalSign && e.Text == "." && textBox.Text.Contains("."))
e.Handled = true;
if (this.AllowDecimalSign && e.Text == ".")
return;
if (!this.IsNumeric(e.Text))
e.Handled = true;
}
private void OnPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var textBox = (TextBox) sender;
textBox.Text = this.ExtractNumericParts(textBox.Text);
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
if(!e.SourceDataObject.GetDataPresent(DataFormats.Text, true))
return;
var textBox = (TextBox)sender;
var preSelection = textBox.Text.Substring(0, textBox.SelectionStart);
var postSelection = textBox.Text.Substring(textBox.SelectionStart
+ textBox.SelectionLength);
var pastedText = (string)e.SourceDataObject.GetData(DataFormats.Text);
if (!this.IsNumeric(preSelection + pastedText + postSelection))
e.CancelCommand();
}
private bool IsNumeric(string text)
{
var result = false;
if(AllowDecimalSign)
{
decimal number;
result = decimal.TryParse(text, out number);
if (!this.AllowNegativeValues)
return result && number >= 0;
}
else
{
int number;
result = Int32.TryParse(text, out number);
if (!this.AllowNegativeValues)
return result && number >= 0;
}
return result;
}
private string ExtractNumericParts(string text)
{
if (this.IsNumeric(text))
return text;
text = this.RemoveIllegalChars(text);
return this.TrimDigitsToInt32Range(text);
}
private string RemoveIllegalChars(string text)
{
var illegalChars = this.AllowNegativeValues
? NonnumericCharsExceptFirstMinus
: NonnumericChars;
return illegalChars.Replace(text, string.Empty);
}
private string TrimDigitsToInt32Range(string numericText)
{
if (string.IsNullOrEmpty(numericText))
return "0";
return this.IsNumeric(numericText)
? numericText
: this.TrimDigitsToInt32Range(
numericText.Remove(numericText.Length - 1));
}
}
AllowDecimalSign
的值始终是 false
并且不反映 IsUseDecimal
的值,即使我也使用了此代码:
AllowDecimalSign="{Binding Path=IsUseDecimal, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
恐怕绑定不适用于任何类型的 DataGridColumns。它们没有 DataContext,也不是可视化树的一部分。
要使列中的绑定起作用,您必须借助代理项来设置 DataContext 或其他类似的解决方法。
VisualBrush
class 在这种情况下,但对于 DataGridColumn
.
我假设 IsUseDecimal
是您的 ViewModel(或 DataGrid 具有的任何 DataContext)中的 属性。
代理元素:
public class DataContextProxy: Freezable
{
public DataContextProxy()
{
BindingOperations.SetBinding(this, DataContextProperty, new Binding());
}
public object DataContext
{
get { return GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
public static readonly DependencyProperty DataContextProperty = FrameworkElement
.DataContextProperty.AddOwner(typeof (DataContextProxy));
protected override Freezable CreateInstanceCore()
{
return new DataContextProxy();
}
}
并将其添加到资源中并在您的专栏中使用它:
<ZF:ZFDataGrid
x:Name="dgvGrid"
HorizontalAlignment="Stretch" VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CanUserAddRows="True"
CanUserDeleteRows="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
CanUserSortColumns="False"
IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
SelectionMode="Single"
ItemsSource="{Binding POSModel}">
<ZF:ZFDataGrid.Resources>
<behavior:DataContextProxy x:Key="Proxy"
DataContext="{Binding}" />
</ZF:ZFDataGrid.Resources>
<ZF:ZFDataGrid.Columns>
<ZF:DataGridNumericColumn
Header="Qty"
Width="80"
AllowDecimalSign="{Binding Path=DataContext.IsUseDecimal,
Source={StaticResource Proxy}}"/>
</ZF:ZFDataGrid.Columns>
</ZF:ZFDataGrid>