簡體   English   中英

在 DataTable 中顯示已刪除的行

[英]Display deleted rows in a DataTable

所以我有一個DataTable ,我綁定到 XAML 中的DataGrid 允許用戶添加、修改和刪除表的行。 我想用特定顏色標記行,具體取決於用戶所做的操作。 例如,如果用戶添加一行,該行將被標記為綠色。 如果用戶修改了一行,則該行將被標記為橙色。 如果用戶刪除該行,該行將被標記為紅色。 我遇到的問題是,一旦我調用row.Delete(); ,刪除的行就不再可見了。 從 model 的角度來看。

有沒有辦法在DataGrid中保持標記為刪除的DataRow 我知道如何實現行背景效果,具體取決於用戶操作。 唯一的問題是我不知道如何保持已刪除的行可見。 這個想法是用戶可以恢復更改或應用它們,這就是應該實際刪除待刪除行的時候。

編輯(添加了關於如何更新行背景顏色的示例):

<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>

我認為,當用戶標記要刪除的行時 - 你應該將它保存在某處(例如int[]數組或List<int> ),然后在用戶完成工作時為該集合中的每個元素調用yourDataGridView.Rows.RemoveAt(index)與表。

也許是這樣的:

//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();
}

而不是索引,您可以保存整個 DataGridRow 並調用yourDataGrid.Remove(wholeRow); . 對於反向刪除,您只需通過刪除顏色並從集合中刪除行索引或整行來取消標記。

如果我理解正確,您需要使用 Delete 鍵而不是刪除行,而是在它們上放置一個標記。 在 DataGrid 中,您需要突出顯示用此標記標記的行的顏色。 你沒有展示你的桌子,所以我將在我的簡單調解中展示。

該示例使用BaseInpc 和 RelayCommand 類

除了它們之外,還使用了命令擴展方法:

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);
  }

}

視圖模型:

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 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>

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);
            }
        }
    }
}

如果您無法使用此示例,請寫下原因並在問題解釋中添加詳細信息。

對附加細節的澄清補充了答案:

我想我應該提到我使用綁定到 DataTrigger 的 DataRow 的 RowState 屬性來更新行背景顏色。 為問題添加了詳細信息。

要控制行的可見性,您需要更改DataTable.DefaultView.RowStateFilter屬性的值。 這在 ViewModel 中並不難做到。

但另一個問題是RowState屬性不會通知其更改。 所以觸發器綁定不會像那樣工作。 在我的示例中,我通過調用Items.Refresh ()解決了這個問題。 也許您正在使用不同的解決方案,因為您還沒有寫過任何與此相關的問題。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM