简体   繁体   English

在 DataTable 中显示已删除的行

[英]Display deleted rows in a DataTable

So I have a DataTable that I bind to the DataGrid in XAML.所以我有一个DataTable ,我绑定到 XAML 中的DataGrid User is allowed to add, modify and remove rows for a table.允许用户添加、修改和删除表的行。 I would like to mark rows with a specific colour, depending on the action that user makes.我想用特定颜色标记行,具体取决于用户所做的操作。 For instance, if user adds a row, that row will be marked as Green.例如,如果用户添加一行,该行将被标记为绿色。 If user modifies a row, that row will then be marked as orange.如果用户修改了一行,则该行将被标记为橙色。 And if user removes the row, that row will be marked as red.如果用户删除该行,该行将被标记为红色。 The problem that I have is that the removed row is no longer visible once I call row.Delete();我遇到的问题是,一旦我调用row.Delete(); ,删除的行就不再可见了。 from a view model.从 model 的角度来看。

Is there a way to keep a DataRow marked for removal shown in a DataGrid ?有没有办法在DataGrid中保持标记为删除的DataRow I know how to achieve the row background effect, depending on user action.我知道如何实现行背景效果,具体取决于用户操作。 The only problem is I don't know how to keep the deleted row visible.唯一的问题是我不知道如何保持已删除的行可见。 The idea is that user can either revert changes or apply them and that's when the pending deletion row should be actually deleted.这个想法是用户可以恢复更改或应用它们,这就是应该实际删除待删除行的时候。

EDIT (Added example on how I update row background colour):编辑(添加了关于如何更新行背景颜色的示例):

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=Row.RowState}" Value="{x:Static data:DataRowState.Deleted}" />
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsSelected}" Value="False" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <Setter Property="Background" Value="IndianRed" TargetName="DGR_Border"/>
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="FontWeight" Value="Bold"/>
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

I think, when user marks row for deleting - you should save it index somewhere ( int[] array or List<int> for example), then call yourDataGridView.Rows.RemoveAt(index) for each element in that collection when user finished working with table.我认为,当用户标记要删除的行时 - 你应该将它保存在某处(例如int[]数组或List<int> ),然后在用户完成工作时为该集合中的每个元素调用yourDataGridView.Rows.RemoveAt(index)与表。

Maybe something like:也许是这样的:

//Collection for rows indexes which will be deleted later
List<int> rowsToDelete = new List<int>();

//Call this when user want to delete element
private void MarkElementsToRemove()
{
   if (yourDataGrid.SelectedItems.Count > 0)
   {
       //Get selected by user rows
       for (int i = 0; i < yourDataGrid.SelectedItems.Count; ++i)
       {
           DataGridRow row = (DataGridRow)yourDataGrid.SelectedItems[i];

           //Fill rows background with some color to mark them visually as "deleted"
           row.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));

           //Get row index to remove it later and add it to collection
           rowsToDelete.Add(row.GetIndex());                        
        }
    }
}

// Call this when user finished work with DataGrid and items may be removed
private void RemoveMarkedElements()
{
   foreach (int index in rowsToDelete)
   {
      yourDataGrid.Items.RemoveAt(index);
   }
   
   rowsToDelete.Clear();
}

Instead of index you may save whole DataGridRow and call yourDataGrid.Remove(wholeRow);而不是索引,您可以保存整个 DataGridRow 并调用yourDataGrid.Remove(wholeRow); . . And for reverse deletion, you just unmark it by removing color and removing row index or whole row from a collection.对于反向删除,您只需通过删除颜色并从集合中删除行索引或整行来取消标记。

If I understood you correctly, you need to use the Delete key not to delete lines, but to put a marker on them.如果我理解正确,您需要使用 Delete 键而不是删除行,而是在它们上放置一个标记。 And in the DataGrid, you need to highlight color the rows marked with this marker.在 DataGrid 中,您需要突出显示用此标记标记的行的颜色。 You have not shown your table, so I will demonstrate in my simple conciliation.你没有展示你的桌子,所以我将在我的简单调解中展示。

The example uses the BaseInpc and RelayCommand classes .该示例使用BaseInpc 和 RelayCommand 类

In addition to them, the command extension method is used:除了它们之外,还使用了命令扩展方法:

using System.Windows.Input;

namespace Simplified
{
    public static class CommandExtensionMethods
    {
        public static bool TryExecute(this ICommand command, object parameter)
        {
            bool can = command.CanExecute(parameter);
            if (can)
                command.Execute(parameter);
            return can;
        }
        public static bool TryExecute(this ICommand command)
          => TryExecute(command, null);
  }

}

ViewModel:视图模型:

using Simplified;
using System.Data;
using System.Windows.Input;

namespace DeferredRowDeletion
{
    public class DrdViewModel : BaseInpc
    {
        public DataTable Table { get; } = new DataTable();
        public DrdViewModel()
        {
            Table.Columns.Add("Name", typeof(string));
            Table.Columns.Add("Value", typeof(int));
            Table.Columns.Add("Marked for deletion", typeof(bool));
            foreach (var name in new string[] { "First", "Second", "Third", "Fourth", "Fifth" })
            {
                var row = Table.NewRow();
                row[0] = name;
                row[1] = Table.Rows.Count;
                row[2] = Table.Rows.Count % 2 == 1;
                Table.Rows.Add(row);
            }
        }

        private ICommand _markRemoveChangeCommand;
        private bool _isRemoveRowsImmediately;

        public ICommand MarkRemoveChangeCommand => _markRemoveChangeCommand
            ?? (_markRemoveChangeCommand = new RelayCommand<DataRow>(
                row => row[2] = !(bool)(row[2] ?? false),
                row => !IsRemoveRowsImmediately
                ));

        public bool IsRemoveRowsImmediately
        {
            get => _isRemoveRowsImmediately;
            set => Set(ref _isRemoveRowsImmediately, value);
        }
    }
}

Window XAML: Window XAML:

<Window x:Class="DeferredRowDeletion.DrdWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DeferredRowDeletion"
        mc:Ignorable="d"
        Title="DrdWindow" Height="450" Width="800">
    <FrameworkElement.DataContext>
        <local:DrdViewModel/>
    </FrameworkElement.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <CheckBox Content="Removw Rows Immediately"
                  IsChecked="{Binding IsRemoveRowsImmediately}"
                  Margin="5"/>
        <DataGrid x:Name="dataGrid" Grid.Row="1"
                  ItemsSource="{Binding Table, Mode=OneWay}"
                  AutoGeneratingColumn="OnAutoGeneratingColumn"
                  CanUserDeleteRows="{Binding IsRemoveRowsImmediately}"
                  PreviewKeyDown="OnPreviewKeyDown">
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding [Marked for deletion]}" Value="true">
                            <Setter Property="Background" Value="HotPink"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>
</Window>

Code Behind Window: Window 后面的代码:

using Simplified;
using System.Data;
using System.Windows;
using System.Windows.Input;

namespace DeferredRowDeletion
{
    public partial class DrdWindow : Window
    {
        public DrdWindow()
        {
            InitializeComponent();
        }
        private void OnAutoGeneratingColumn(object sender, System.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)
        {
            if (e.PropertyName == "Marked for deletion")
                e.Cancel = true;
        }

        private void OnPreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
            {
                DrdViewModel viewModel = (DrdViewModel)DataContext;
                var rowView = dataGrid.CurrentItem as DataRowView;
                if (rowView != null && !rowView.IsEdit)
                    viewModel.MarkRemoveChangeCommand.TryExecute(rowView.Row);
            }
        }
    }
}

If you are unable to use this example, then write the reason and add details to the explanation of your question.如果您无法使用此示例,请写下原因并在问题解释中添加详细信息。

The answer is supplemented by clarifications for the added details:对附加细节的澄清补充了答案:

I think I should've mentioned that I use DataRow's RowState property bound to the DataTrigger to update row background colour.我想我应该提到我使用绑定到 DataTrigger 的 DataRow 的 RowState 属性来更新行背景颜色。 Added details to the question.为问题添加了详细信息。

To control the visibility of rows, you need to change the value of the DataTable.DefaultView.RowStateFilter property.要控制行的可见性,您需要更改DataTable.DefaultView.RowStateFilter属性的值。 This is not hard to do in the ViewModel.这在 ViewModel 中并不难做到。

But an additional problem is that the RowState property does not notify about its change.但另一个问题是RowState属性不会通知其更改。 So the trigger binding won't work just like that.所以触发器绑定不会像那样工作。 In my example, I solved this by calling Items.Refresh () .在我的示例中,我通过调用Items.Refresh ()解决了这个问题。 Perhaps you are using a different solution since you have not written about any problems associated with this.也许您正在使用不同的解决方案,因为您还没有写过任何与此相关的问题。

using Simplified;
using System.Data;
using System.Windows.Input;

namespace DeferredRowDeletion
{
    public class ShowDeletedRowsViewModel : BaseInpc
    {
        public DataTable Table { get; } = new DataTable();
        public ShowDeletedRowsViewModel()
        {
            Table.Columns.Add("Name", typeof(string));
            Table.Columns.Add("Value", typeof(int));
            foreach (var name in new string[] { "First", "Second", "Third", "Fourth", "Fifth" })
            {
                var row = Table.NewRow();
                row[0] = name;
                row[1] = Table.Rows.Count;
                Table.Rows.Add(row);
            }
            // Commits all the changes 
            Table.AcceptChanges();

            Table.Rows[1].Delete();
            Table.Rows[3].Delete();

            // Show Deleded Rows
            IsVisibilityDelededRows = true;
        }

        private ICommand _markRemoveChangeCommand;
        private bool _isVisibilityDelededRows;

        public ICommand MarkRemoveChangeCommand => _markRemoveChangeCommand
            ?? (_markRemoveChangeCommand = new RelayCommand<DataRow>(
                row => IsVisibilityDelededRows ^= true,
                row => !IsVisibilityDelededRows
                ));

        public bool IsVisibilityDelededRows
        {
            get => _isVisibilityDelededRows;
            set => Set(ref _isVisibilityDelededRows, value);
        }

        protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);

            if (propertyName == nameof(IsVisibilityDelededRows))
            {
                // Change the row filter if the associated property has changed
                if (IsVisibilityDelededRows)
                {
                    Table.DefaultView.RowStateFilter |= DataViewRowState.Deleted;
                }
                else
                {
                    Table.DefaultView.RowStateFilter &= ~DataViewRowState.Deleted;
                }
            }
        }
    }
}
<Window x:Class="DeferredRowDeletion.SdrWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DeferredRowDeletion" xmlns:data="clr-namespace:System.Data;assembly=System.Data"
        mc:Ignorable="d"
        Title="SdrWindow" Height="450" Width="800">
    <FrameworkElement.DataContext>
        <local:ShowDeletedRowsViewModel/>
    </FrameworkElement.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel>
            <CheckBox x:Name="cbAutoRefresh" Content="Auto Items.Refresh()" IsChecked="True" Margin="5"/>
            <CheckBox Content="Visibility Deleded Rows"
                  IsChecked="{Binding IsVisibilityDelededRows}"
                  Margin="5"/>
        </StackPanel>
        <DataGrid x:Name="dataGrid" Grid.Row="1"
                  ItemsSource="{Binding Table, Mode=OneWay}"
                  PreviewKeyUp="OnPreviewKeyUp">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Path=Row.RowState, Mode=OneWay}"
                                    Header="RowState"/>
            </DataGrid.Columns>
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=Row.RowState}" Value="{x:Static data:DataRowState.Deleted}">
                            <Setter Property="Background" Value="HotPink"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>
</Window>
        private void OnPreviewKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Delete && cbAutoRefresh.IsChecked == true)
                dataGrid.Items.Refresh();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 DataTable 已删除行问题 - DataTable Deleted Rows Issues ViewState中的DataTable正在返回已删除的行 - DataTable in ViewState is Returning Deleted Rows 从DataTable访问已删除的行 - Accessing deleted rows from a DataTable C#DataTable中已删除的行数 - C# Number of deleted rows in DataTable Datatable.Load不会删除已删除的行 - Datatable.Load doesn't remove deleted rows 绑定到DataTable的Datagrid不会显示动态添加到DataTable的任何行 - Datagrid that is bound to DataTable does not display any rows that are added dynamically to DataTable 我试图将两个数据表合并为一个并显示在gridview中,但数据表值显示在不同的行中 - i am trying to merge two datatable into one and display in the gridview but the datatable values display in different rows C# - 两个数据表比较。 获取更新、删除和创建的行(新) - C# - Two DataTable comparison. Get Rows which are Updated, Deleted and Created(New) “无法通过行”尝试从我的数据表中删除未使用的行来删除已删除的行信息 - “Deleted row information cannot be accessed through the row” trying to remove unused rows from my datatable 将行从GridView绑定到DataTable并将其显示在另一个GridView RSS中 - Bind Rows From GridView to DataTable and Display It In Another GridView RSS
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM