【问题标题】:How to validate datagridcell value based on previous value如何根据先前的值验证 datagridcell 值
【发布时间】:2017-02-25 19:21:04
【问题描述】:

我创建了一个多行多列的数据网格。其中一列是用户可以更改的字段大小列表。

我正在根据旧值检查新值,如果新值小于旧值,我告诉用户这是无效的,然后我想放回旧值并将焦点重新设置到该单元格.

我的LostFocus 活动中有这一行:

System.Windows.Controls.TextBox tbNewSize = 
    (System.Windows.Controls.TextBox)dtgCell.Content;

当我点击单元格时,LostFocus 事件被调用并且工作正常。但是,当我尝试重新聚焦到单元格时,我收到一条错误消息

“无法将“System.Windows.Controls.TextBlock”类型的对象转换为“System.Windows.Controls.TextBox”类型。”

我该如何解决这个问题?

这是我的 XAML 代码:

<DataGrid HeadersVisibility="Column" Name="dtGrid" Loaded="GridLoaded" AutoGenerateColumns="False" IsReadOnly="False" VirtualizingPanel.IsVirtualizing="False" Height="365" Width="530" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="54,74,0,0" BorderThickness="1,1,0,1" BorderBrush="Black">
<DataGrid.Columns>
    <DataGridTextColumn Header="Field" Binding="{Binding Field, Mode=TwoWay}" Width="209" IsReadOnly="True" />
    <DataGridTextColumn Header="Size" Binding="{Binding Size, Mode=TwoWay}" Width="89"/>
    <DataGridCheckBoxColumn Header="Right Justify" Binding="{Binding RightJustify, Mode=TwoWay}" Width="55" />
    <DataGridCheckBoxColumn Header="Left Justify" Binding="{Binding LeftJustify, Mode=TwoWay}"  Width="55"  />
    <DataGridCheckBoxColumn Header="Left Zero Fill" Binding="{Binding LeftZeroFill, Mode=TwoWay}" Width="55" />
    <DataGridCheckBoxColumn Header="Right Zero Fill" Binding="{Binding RightZeroFill, Mode=TwoWay}" Width="65" />
</DataGrid.Columns>
<DataGrid.ColumnHeaderStyle>
    <Style TargetType="DataGridColumnHeader">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <TextBlock TextWrapping="Wrap" Text="{Binding}"></TextBlock>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Resources>
    <Style TargetType="{x:Type DataGridCell}">
        <Style.Triggers>
            <Trigger Property="DataGridCell.IsSelected" Value="True">
                <Setter Property="Background" Value="#FF9DF3D6" />
                <Setter Property="Foreground" Value="#000000" />
            </Trigger>
        </Style.Triggers>
        <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
        <EventSetter Event="LostFocus" Handler="DataGridCell_OnCellLostFocus" />
    </Style>
</DataGrid.Resources>

这是我的 C# 代码:

private void DataGridCell_OnCellLostFocus(object sender, RoutedEventArgs e)
{
    System.Windows.Controls.DataGridCell dtgCell = (System.Windows.Controls.DataGridCell)sender;

    if (dtgCell.Column.Header.ToString() == "Size")
    {
        System.Windows.Controls.TextBox tbNewSize = (System.Windows.Controls.TextBox)dtgCell.Content;
        Int32 intNewSize = Convert.ToInt32(tbNewSize.Text);
        Int32 intCurrSize = Convert.ToInt32(strFieldInfoOrig[dtGrid.Items.IndexOf(dtGrid.CurrentItem), 1]);

        if (intNewSize < intCurrSize)
        {
            string strMsg;

            strMsg = "New size, " + intNewSize.ToString() + " is smaller then the original size, " + intCurrSize.ToString();
            strMsg += Environment.NewLine;
            strMsg += "Due to potential data loss, this is not allowed.";
            System.Windows.MessageBox.Show(strMsg);
            //dtgCell.Content = intCurrSize.ToString();
            dtgCell.Focus();
        }
    }
}

【问题讨论】:

  • 我在Int32 intCurrSize = Convert.ToInt32(strFieldInfoOrig[dtGrid.Items.IndexOf(dtGrid.CurrentItem), 1]); 这一行收到一个错误,导致代码无法编译 - 你确定这是正确的吗?
  • #Bassue - 这对我有用。在第一次运行时,我输入了一个较小的数字,然后进入 if 语句和错误消息。

标签: c# wpf validation datagrid lostfocus


【解决方案1】:

您可以处理CellEditEnding 事件。

<DataGrid AutoGenerateColumns="False"
          CellEditEnding="DataGrid_CellEditEnding"
          ...
          >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Size" Binding="{Binding Size, Mode=TwoWay}" .../>

        ...

    </DataGrid.Columns>

    ...
    
</DataGrid>

后面的代码

private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) 
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        if (e.Column is DataGridBoundColumn)
        {
            DataGridBoundColumn column = (DataGridBoundColumn)e.Column;
            if (column.Header.ToString() == "Size")
            {
                string oldValue = e.Row.DataContext.GetType().GetProperty("Size")
                                   .GetValue(e.Row.DataContext).ToString();
                TextBox element = e.EditingElement as TextBox;
                string newValue = element.Text;
                int oldSize = int.Parse(oldValue);
                int newSize = int.Parse(newValue);
                if (newSize < oldSize)
                {
                    string strMsg = "New size, " + newValue + ", is smaller then the original size, "
                                  + oldValue + ".\nDue to potential data loss, this is not allowed.";
                    MessageBox.Show(strMsg);
                    element.Text = oldValue;
                    e.Cancel = true;
                }
            }
        }
    }
}

设置e.Cancel = true 使单元格保持在编辑模式。

【讨论】:

  • #bab7lon - 它在字符串 oldValue = e.Row.DataContext.GetType().GetProperty("Size") .GetValue(e.Row.DataContext).ToString() 上失败;看来 .GetProperty("Size") 正在返回 null,我认为
  • @Cass 你如何在Loaded 上填写DataGrid?您是否使用DataTable,...将ItemsSource 绑定到集合?
  • 是的,我用这些值加载了一个数据表,然后将其绑定到 datagrid.ItemsSource, dtGrid.ItemsSource = dtGridData.DefaultView;我能够解决这个错误,DataRowView drvRowView = (DataRowView)e.Row.DataContext;字符串 oldValue = drvRowView.Row.ItemArray[1].ToString();
  • @Cass 这么想,我的 sn-p 是用于集合的。所以你已经启动并运行了?
  • 是的,我正在运行它。它将旧值放回原处并使单元格保持在编辑模式,但重点是下一个单元格,我想选择旧单元格和值。我试过 element.focus();但这不起作用。
【解决方案2】:

这是因为DataGridTextColumn 在正常模式下显示TextBlock 而在编辑时显示TextBox。因此,当此单元格失去焦点时,DataGridTextColumn 会以正常模式返回,因此其内容将是TextBlock 而不是TextBox,因此会显示异常。

因此,请尝试转换为 TextBlock 而不是 TextBox

【讨论】:

    【解决方案3】:

    您正在尝试将TextBlock 转换为TextBox,这显然行不通。但是,如果您只是尝试始终像这样转换为 TextBlock

    System.Windows.Controls.TextBlock tbNewSize = (System.Windows.Controls.TextBlock)dtgCell.Content;
    

    ...这也行不通。这是因为单元格的 Content 可能是 TextBox TextBlock,具体取决于单元格当前是否处于编辑模式。

    您可以使用as 运算符尝试 转换为TextBox,如果转换失败,则将Content 属性转换为TextBlock

    private void DataGridCell_OnCellLostFocus(object sender, RoutedEventArgs e)
    {
        System.Windows.Controls.DataGridCell dtgCell = (System.Windows.Controls.DataGridCell)sender;
        if (dtgCell.Column.Header.ToString() == "Size")
        {
            string text = null;
            System.Windows.Controls.TextBox tbNewSize = dtgCell.Content as System.Windows.Controls.TextBox;
            if (tbNewSize != null)
            {
                text = tbNewSize.Text;
            }
            else
            {
                System.Windows.Controls.TextBlock tb = dtgCell.Content as System.Windows.Controls.TextBlock;
                if (tb != null)
                    text = tb.Text;
            }
            Int32 intNewSize = Convert.ToInt32(text);
            Int32 intCurrSize = Convert.ToInt32(strFieldInfoOrig[dtGrid.Items.IndexOf(dtGrid.CurrentItem), 1]);
    
            if (intNewSize < intCurrSize)
            {
                string strMsg;
    
                strMsg = "New size, " + intNewSize.ToString() + " is smaller then the original size, " + intCurrSize.ToString();
                strMsg += Environment.NewLine;
                strMsg += "Due to potential data loss, this is not allowed.";
                System.Windows.MessageBox.Show(strMsg);
                //dtgCell.Content = intCurrSize.ToString();
                dtgCell.Focus();
            }
        }
    }
    

    【讨论】:

    • #bab7lon -- 我现在正在尝试,抱歉耽搁了,我的电脑崩溃了,我现在刚刚恢复
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 1970-01-01
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多