WPF,Datagrid自定义DataGridTextColumn DependencyProperty不起作用

时间:2015-06-23 02:25:37

标签: wpf wpfdatagrid dependency-properties

我有以下自定义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 Pattern。 IsUseDecimalboolean属性。 而且,我创建了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}">

1 个答案:

答案 0 :(得分:0)

绑定不适用于任何类型的DataGridColumns,我很害怕。他们没有DataContext,他们不属于可视树。

要使列中的绑定起作用,您必须使用代理项来设置DataContext或其他类似的解决方法。

I explained the proxy item approach here,对于VisualBrush类,对于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>