[英]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.