wpf DataGrid 使用数据模板中的自定义控件自动编辑单元格

本文关键字:自定义控件 单元格 编辑 DataGrid 数据 wpf | 更新日期: 2023-09-27 18:36:01

我有一个wpf数据网格,每行都有一些拥抱行和一些可编辑的单元格。

我想使单元格在用户导航到它时可编辑,而不是使用单击或 dbl 单击。 像Excel这样的东西。

1-数据网格可以吗? 如何执行?

2-如何让用户使用箭头键提交单元格更改?

更新:

<DataGrid x:Name="DataGridDatosPlanillla" Margin="5" Grid.Row="1" Width="Auto" Height="Auto" Grid.ColumnSpan="2" CanUserReorderColumns="False" AutoGenerateColumns="False" 
            ItemsSource="{Binding Path=PlanillaDetalle}" SelectionChanged="DataGridDatosPlanillla_SelectionChanged"
            Style="{StaticResource ResourceKey=Datagridstyle}" KeyboardNavigation.AcceptsReturn="True" KeyboardNavigation.DirectionalNavigation="Contained" BeginningEdit="DataGridDatosPlanillla_BeginningEdit" CurrentCellChanged="DataGridDatosPlanillla_CurrentCellChanged" FocusableChanged="DataGridDatosPlanillla_FocusableChanged">
    <DataGrid.Columns>
        <DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=Orden}" ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.GENERAL_IdFila}" CanUserSort="False"/>
        <DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=Merlin_Contratos.StrNombreUsuario}" ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.ACOPIO_NombreTercero}" CanUserSort="False"/>
        <DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=Merlin_ConceptosFacturacion.StrDescripcionConcepto}" ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.ITEMS_Nombre}" CanUserSort="False"/>
        <DataGridTemplateColumn ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.ACOPIO_Recogida1}" CanUserSort="False">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <controls:NumericTextBox DecimalPlaces="{Binding Path=Merlin_ConceptosFacturacion.IntPlazasDecimales}" Text="{Binding Path=QProductor1}" BorderThickness="0"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.ACOPIO_CantidadDescontada}" CanUserSort="False" CanUserResize="False">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <controls:NumericTextBox DecimalPlaces="{Binding Path=Merlin_ConceptosFacturacion.IntPlazasDecimales}" Text="{Binding Path=QDescontada}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn IsReadOnly="True" ClipboardContentBinding="{x:Null}" Header="{x:Static resources:Labels.ACOPIO_TotalRecibido}" CanUserSort="False" CanUserResize="False">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <controls:NumericTextBox DecimalPlaces="{Binding Path=Merlin_ConceptosFacturacion.IntPlazasDecimales}" Text="{Binding Path=QRecibida}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

这是我的自定义控件

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Recursos.Controls
{
    public class CustomFormat : IFormatProvider, ICustomFormatter
    {
        int DecimalPlaces = 0; 
        public CustomFormat(int decimalPlaces)
        {
            DecimalPlaces = decimalPlaces;
        }
        public object GetFormat(Type FormatType)
        {
            if (FormatType == typeof(ICustomFormatter))
                return this;
            else
                return null;
        }
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            if (!this.Equals(formatProvider))
                return null;
            if (string.IsNullOrEmpty(format))
                format = "N";
            string numericString = arg.ToString();
            return numericString;
        }
    }

    public class NumericTextBox : TextBox
    {
        #region Formato
        private string previousText = "";
        private bool ApplyingFormat = false;
        private CultureInfo _CI = new CultureInfo(CultureInfo.CurrentCulture.LCID,true);
        public CultureInfo CI
        {
            get { return _CI; }
            set { _CI = value; }
        }
        public static readonly DependencyProperty DecimlaPlacesProperty = DependencyProperty.Register(
            "DecimalPlaces", 
            typeof(int), 
            typeof(NumericTextBox),
            new FrameworkPropertyMetadata(0,
                FrameworkPropertyMetadataOptions.None,
                new PropertyChangedCallback(OnDecimalPlacesChanged)
                )
        );
        private static void OnDecimalPlacesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        /// <summary>
        /// Numero de plazas decimales 
        /// </summary>
        public int DecimalPlaces
        {
            get { return (int)GetValue(DecimlaPlacesProperty); }
            set { SetValue(DecimlaPlacesProperty,value); _CI.NumberFormat.NumberDecimalDigits = value; }
        }
        public Decimal DecimalValue = 0;
        private string _DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        public string DecimalSeparator
        {
            get { return _DecimalSeparator; }
            set { _DecimalSeparator = value; _CI.NumberFormat.NumberDecimalSeparator = _DecimalSeparator; }
        }
        //public string DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        #endregion 

        public NumericTextBox()
        {
            HorizontalContentAlignment = HorizontalAlignment.Right;
            DataObject.AddPastingHandler(this, OnPaste);
        }
        private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
        {
            var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
            if (isText)
            {
                var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
                if (IsTextValid(text))
                {
                    return;
                }
            }
            dataObjectPastingEventArgs.CancelCommand();
        }
        private bool IsTextValid(string enteredText)
        {
            //  If keyboard insert key is in toggled mode, and the actual insert point is Decimalseparator, we must avoid to overwrite it
            if (SelectionStart == this.Text.IndexOf(DecimalSeparator)
                & System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.Insert) == System.Windows.Input.KeyStates.Toggled)
            {
                SelectionStart += 1;
            }
            if (!enteredText.All(c => Char.IsNumber(c) || c == DecimalSeparator.ToCharArray()[0] || c == '-'))
            {
                return false;
            }
            //We only validation against unselected text since the selected text will be replaced by the entered text
            var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);
            if ( enteredText == DecimalSeparator && unselectedText.Contains(DecimalSeparator))
            {
                //  Before return false, must move cursor beside Decimal separator
                SelectionStart = this.Text.IndexOf(DecimalSeparator) + 1;
                return false;
            }
            if (enteredText == "-" && unselectedText.Length > 0)
            {
                return false;
            }
            return true;
        }
        private bool ApplyFormat(TextChangedEventArgs e)
        {
            if (!ApplyingFormat)
            {
                ApplyingFormat = true;
                int SelectionStartActual = SelectionStart;
                string FinallText = this.Text;
                if (!FinallText.Contains(DecimalSeparator) & DecimalPlaces > 0)
                {
                    FinallText = String.Format("{0}{1}{2}", this.Text, DecimalSeparator, new string('0', DecimalPlaces));
                }
                bool state = Decimal.TryParse(FinallText, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint | NumberStyles.AllowTrailingSign, _CI, out DecimalValue);
                DecimalValue = Math.Round(DecimalValue, DecimalPlaces);
                if (DecimalValue == 0)
                {
                    FinallText = "";
                }
                else
                {
                    if (FinallText != DecimalValue.ToString(_CI))
                    {
                        FinallText = DecimalValue.ToString(_CI);
                    }
                }
                if (FinallText != this.Text)
                {
                    this.Text = FinallText;
                    SelectionStart = SelectionStartActual;
                }
                previousText = this.Text;
                ApplyingFormat = false;
                return state;
            }
            else
            {
                return true;
            }
        }
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            e.Handled = !ApplyFormat(e);
            base.OnTextChanged(e);
        }
        protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
        {
            e.Handled = !IsTextValid(e.Text);
            base.OnPreviewTextInput(e);
        }
    }
}

wpf DataGrid 使用数据模板中的自定义控件自动编辑单元格

private void DataGrid_GotFocus(object sender, RoutedEventArgs e)
{
    // Lookup for the source to be DataGridCell
    if (e.OriginalSource.GetType() == typeof(DataGridCell))
    {
        // Starts the Edit on the row;
        DataGrid grd = (DataGrid)sender;
        grd.BeginEdit(e);
    }
}