Click here to Skip to main content
15,880,972 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I give credit to whoever answers this question by posting the output.
If my country's banks were not sanctioned, I would give a gift to the individual who answered this question (I've been looking for an acceptable response for months).


I want the rows that the user selects to be deleted.
As far as I know, the DataGrid.ItemsSource cannot be removed directly using the DataGrid.Items.Remove() method, so I must convert the DataGrid.ItemsSource to a DataTable and use the DataGrid.ItemsSource = DataTable.DefaultView property.
To convert DataGrid.ItemsSource to DataTable, I tried the following solutions in various situations, and each has advantages and disadvantages (I spent several months researching and testing):

What I have tried:

First solution (I made this by myself):
XAML
<DataGrid x:Name="BookDataGrid" EnableRowVirtualization="True" VirtualizingPanel.ScrollUnit="Pixel" CanUserAddRows="False" BeginningEdit="BookDataGrid_BeginningEdit" RowEditEnding="BookDataGrid_RowEditEnding" HeadersVisibility="Column" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="386" Width="486" Margin="0">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="BookName" Binding="{Binding BookName}" Width="SizeToHeader">
            <DataGridTextColumn.EditingElementStyle>
                <Style TargetType="TextBox">
                    <Setter Property="AcceptsReturn" Value="True"/>
                    <Setter Property="ContextMenu" Value="{StaticResource CustomContextMenu}"/>
                    <Setter Property="TextWrapping" Value="WrapWithOverflow"/>
                </Style>
            </DataGridTextColumn.EditingElementStyle>
        </DataGridTextColumn>
        <DataGridTemplateColumn x:Name="BookImage" Width="SizeToHeader">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image x:Name="BookImg" Source="{Binding BookImage}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
C#
public byte[] ImageSourceToBytes(BitmapEncoder BitEncoder, ImageSource ImgSource)
{
    byte[] Bytes = null;
    switch ((ImgSource as BitmapSource) != null)
    {
        case true:
            BitEncoder.Frames.Add(BitmapFrame.Create((ImgSource as BitmapSource)));
            using (var Stream = new System.IO.MemoryStream())
            {
                BitEncoder.Save(Stream);
                Bytes = Stream.ToArray();
            }
            break;
    }
    return Bytes;
}
public DataTable DataGridToDataTable(DataGrid DG, DataTable DT, byte NumberOfColumns, byte VisualColumnIndex, string ControlName)
{
    for (int i = 0; i < DG.Items.Count; i++)
    {
        DT.Rows.Add(DG.Items[i]);
    }
    for (int i = 0; i < DG.Items.Count; i++)
    {
        for (byte j = 0; j < NumberOfColumns; j++)
        {
            switch (j == VisualColumnIndex)
            {
                case true:
                    FrameworkElement FE = DG.Columns[j].GetCellContent((DataGridRow)DG.ItemContainerGenerator.ContainerFromIndex(i));
                    Image Img = new Image() { Source = ((((DataGridTemplateColumn)DG.Columns[j]).CellTemplate.FindName(ControlName, FE) as Image).Source) };
                    DT.Rows[i][j] = ImageSourceToBytes(new PngBitmapEncoder(), Img.Source);
                    break;
                default:
                    DG.ScrollIntoView((DataRowView)DG.Items[i]);
                    DT.Rows[i][j] = ((DG.Columns[j].GetCellContent(((DataGridRow)DG.ItemContainerGenerator.ContainerFromIndex(i)))) as TextBlock).Text;
                    break;
            }
        }
    }
    return DT;
}
Advantage: Even if one of the columns is of the Image type, this approach operates without an error.
Disadvantage: The method DG.ScrollIntoView((DataRowView)DG.Items[i]) must be used when the EnableRowVirtualization attribute is set to True; otherwise, a null error will occur. For large numbers of rows, this approach is incredibly sluggish (e.g., if we have 20,000 rows, it could take an hour or more).

Second solution (I made this by myself):
XAML
<DataGrid x:Name="BookDataGrid" EnableRowVirtualization="False" CanUserAddRows="False" BeginningEdit="BookDataGrid_BeginningEdit" RowEditEnding="BookDataGrid_RowEditEnding" HeadersVisibility="Column" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="386" Width="486" Margin="0">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="BookName" Binding="{Binding BookName}" Width="SizeToHeader">
            <DataGridTextColumn.EditingElementStyle>
                <Style TargetType="TextBox">
                    <Setter Property="AcceptsReturn" Value="True"/>
                    <Setter Property="ContextMenu" Value="{StaticResource CustomContextMenu}"/>
                    <Setter Property="TextWrapping" Value="WrapWithOverflow"/>
                </Style>
            </DataGridTextColumn.EditingElementStyle>
        </DataGridTextColumn>
        <DataGridTemplateColumn x:Name="BookImage" Width="SizeToHeader">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image x:Name="BookImg" Source="{Binding BookImage}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
C#
public DataTable DataGridToDataTable(DataGrid DG, DataTable DT, byte NumberOfColumns, byte VisualColumnIndex, string ControlName)
{
    for (int i = 0; i < DG.Items.Count; i++)
    {
        DT.Rows.Add(DG.Items[i]);
    }
    for (int i = 0; i < DG.Items.Count; i++)
    {
        for (byte j = 0; j < NumberOfColumns; j++)
        {
            switch (j == VisualColumnIndex)
            {
                case true:
                    FrameworkElement FE = DG.Columns[j].GetCellContent((DataGridRow)DG.ItemContainerGenerator.ContainerFromIndex(i));
                    Image Img = new Image() { Source = ((((DataGridTemplateColumn)DG.Columns[j]).CellTemplate.FindName(ControlName, FE) as Image).Source) };
                    DT.Rows[i][j] = ImageSourceToBytes(new PngBitmapEncoder(), Img.Source);
                    break;
                default:
                    DT.Rows[i][j] = ((DG.Columns[j].GetCellContent(((DataGridRow)DG.ItemContainerGenerator.ContainerFromIndex(i)))) as TextBlock).Text;
                    break;
            }
        }
    }
    return DT;
}
Advantage: This solution converts DataGrid.ItemsSource to DataTable faster than the first because EnableRowVirtualization is equal to False in this case.
Disadvantage: This solution consumes a lot of memory; for example, if we have 100,000 rows and the database table is 2GB in size, it will consume 2GB of RAM and a RAM space error may occur.
After running the app (click on this link to view the image)

Third solution:
XAML
<DataGrid x:Name="BookDataGrid" EnableRowVirtualization="True" VirtualizingPanel.ScrollUnit="Pixel" CanUserAddRows="False" BeginningEdit="BookDataGrid_BeginningEdit" RowEditEnding="BookDataGrid_RowEditEnding" HeadersVisibility="Column" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="386" Width="486" Margin="0">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="BookName" Binding="{Binding BookName}" Width="SizeToHeader">
            <DataGridTextColumn.EditingElementStyle>
                <Style TargetType="TextBox">
                    <Setter Property="AcceptsReturn" Value="True"/>
                    <Setter Property="ContextMenu" Value="{StaticResource CustomContextMenu}"/>
                    <Setter Property="TextWrapping" Value="WrapWithOverflow"/>
                </Style>
            </DataGridTextColumn.EditingElementStyle>
        </DataGridTextColumn>
        <DataGridTemplateColumn x:Name="BookImage" Width="SizeToHeader">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image x:Name="BookImg" Source="{Binding BookImage}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

C#
uint[] BookCodeSelectedItems = null; //I need this for further calculations
private void DataGridDeleteMenu_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    switch (BookDataGrid.SelectedItems.Count > 0)
    {
        case true:
            List<object> DefaultRow = new List<object>();
            DataTable BDT = ((DataView)BookDataGrid.ItemsSource).ToTable(); //The first time the event is executed, no error occurs, but the second time the error occurs on this line
            for (int i = 0; i < BookDataGrid.Items.Count; i++)
            {
                DefaultRow.Add(BookDataGrid.Items[i]);
            }
            BookCodeSelectedItems = new uint[BookDataGrid.SelectedItems.Count];
            for (int i = 0; i < BookDataGrid.SelectedItems.Count; i++)
            {
                BookCodeSelectedItems[i] = uint.Parse(BDT.Rows[i][3].ToString());
                DefaultRow.Remove(BookDataGrid.SelectedItems[i]);
            }
            BookDataGrid.ItemsSource = DefaultRow;
            break;
    }
}
Advantage: The DataGrid.ItemsSource is rapidly changed to DataTable in this approach when the DataGridDeleteMenu PreviewMouseLeftButtonDown event is fired for the first time.
Disadvantage: However, when the event is re-run, a System.InvalidCastException: 'Unable to cast object of type 'System.Collections.Generic.List 1[System.Object]' to type 'System.Data.DataView'.' error occurs.
Error (click on this link to view the image)

I use the following tools:
XAML
<Window.Resources>
    <local:DatabaseDataSet x:Key="Database_DataSet"/>
    <CollectionViewSource x:Key="BookTableViewSource" Source="{Binding BookTable, Source={StaticResource Database_DataSet}}"/>
    <CollectionViewSource x:Key="MemberTableViewSource" Source="{Binding MemberTable, Source={StaticResource Database_DataSet}}"/>
</Window.Resources>
<Grid DataContext="{StaticResource BookTableViewSource}" Width="486" Height="386">
    <DataGrid x:Name="BookDataGrid" HeadersVisibility="Column" EnableRowVirtualization="True" VirtualizingPanel.ScrollUnit="Pixel" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="486" Height="386" Margin="0">
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="BookName" Binding="{Binding BookName}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Publisher" Binding="{Binding Publisher}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Category" Binding="{Binding Category}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="BookCode" Binding="{Binding BookCode}" IsReadOnly="True" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Inventory" Binding="{Binding Inventory}" IsReadOnly="True" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ReleaseDate" Binding="{Binding ReleaseDate}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="DateTaken" Binding="{Binding DateTaken}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ReturnDate" Binding="{Binding ReturnDate}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="RecipientName" Binding="{Binding RecipientName}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Language" Binding="{Binding BookLanguage}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Length" Binding="{Binding Length}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Form" Binding="{Binding Form}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Translator" Binding="{Binding Translator}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Narrator" Binding="{Binding Narrator}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ISBN" Binding="{Binding ISBN}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Location" Binding="{Binding Location}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Price" Binding="{Binding Price}" Width="SizeToHeader"/>
            <DataGridTemplateColumn x:Name="BookImage" Width="SizeToHeader">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image x:Name="BookImg" Source="{Binding BookImage}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
C#
public void BookDatagridRefresh()
{
    DatabaseDataSet Database_DataSet = ((DatabaseDataSet)TryFindResource("Database_DataSet"));
    DatabaseDataSetTableAdapters.BookTableTableAdapter BookTable_TableAdapter = new DatabaseDataSetTableAdapters.BookTableTableAdapter();
    BookTable_TableAdapter.Fill(Database_DataSet.BookTable);
    BookDataGrid.ItemsSource = Database_DataSet.Tables["BookTable"].DefaultView;
}
Visual Studio 2017, .NET Framework 4.5.2, WPF
Binding (click on this link to view the image)
Thank you for your attention.
Posted
Updated 17-Jul-22 18:16pm
v2
Comments
Richard Deeming 14-Jul-22 3:52am    
BookDataGrid.ItemsSource = DefaultRow;

After that line executes, the ItemsSource is no longer a DataView; it's a List<object>.

You can't cast a List<object> to a DataView.
Reza jafery 14-Jul-22 13:01pm    
Yes, you are right, I tested the following code (I put a breakpoint):
var dataType = BookDataGrid.ItemsSource.GetType().BaseType;

For the first time:
Value= {Name = "MarshalByValueComponent" FullName = "System.ComponentModel.MarshalByValueComponent"}
Type= System.Type {System.RuntimeType}
For the second time:
Value= {Name = "Object" FullName = "System.Object"}
Type= System.Type {System.RuntimeType}
It seems that only the value has changed.
But what is the solution?
Richard Deeming 15-Jul-22 4:03am    
The solution is to not change the type of the ItemsSource. Instead, filter the data source in-place.
How to: Group, sort, and filter Data in the DataGrid control - WPF .NET Framework | Microsoft Docs[^]
Reza jafery 19-Jul-22 22:39pm    
Again, you are correct. After tinkering with the solutions mentioned above, I finally found the right solution.
I made a strategic mistake. When we connect "DataGrid.ItemsSource" to "DataView" or "CollectionViewSource.Source" for the first time, the values of "DataView" and "CollectionViewSource.Source" change automatically with each change (like insert, edit, and delete), so the code that connects "DataGrid.ItemsSource" to "DataView" or "CollectionViewSource.Source" does not need to be rewritten.Again, you are correct. After tinkering with the solutions mentioned above, I finally found the right solution.
I made a strategic mistake. When we connect "DataGrid.ItemsSource" to "DataView" or "CollectionViewSource.Source" for the first time, the values of "DataView" and "CollectionViewSource.Source" change automatically with each change (like insert, edit, and delete), so the code that connects "DataGrid.ItemsSource" to "DataView" or "CollectionViewSource.Source" does not need to be rewritten. ◉‿◉
Reza jafery 18-Jul-22 0:29am    
Do you think my solution still has problems?
Please see the output of my solution. I tested it.
Do you still believe there could be a problem with the solution I offered?
Thank you for your attention.

Simply use an ObservableCollection as the ItemSource. The DataGrid them becomes the "View" into the data. Now simply removing items from the ObservableCollection will be reflected in the DataGrid.`

Here is a simple example:

1. Class to hold a row:
C#
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

2. The code-behind with the ObservableCollection:
C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public ObservableCollection<Person> Items { get; set; } = new()
    {
        new() { Name = "Freddie", Age = 21 },
        new() { Name = "Milly", Age = 18 },
        new() { Name = "Caddie", Age = 23 },
    };

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items.RemoveAt(0);
    }
}

3. The View:
XML
<Grid DataContext="{Binding ElementName=Window1}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <DataGrid ItemsSource="{Binding Items}"/>
    <Button Content="Delete First Row"
            Click="Button_Click"
            Grid.Row="1" Width="200"
            Padding="10" Margin="10" />
</Grid>

Now when you click the button, the first Row of the collection is removed, the ObservableCollection raises a CollectionChanged which the DataGrid will capture via the DataBinding and will update itself.
 
Share this answer
 
v3
Comments
Reza jafery 13-Jul-22 18:59pm    
Thank you for your time and feedback.
I'll review your response and notify you of the outcome.
Finally, I found a solution that does not have the above problems.

I made a strategic mistake. When we connect DataGrid.ItemsSource to DataView or CollectionViewSource.Source for the first time, the values of DataView and CollectionViewSource.Source change automatically with each change (like insert, edit, and delete), so the code that connects DataGrid.ItemsSource to DataView or CollectionViewSource.Source does not need to be rewritten.

Look carefully at the image below to get a better understanding of how this feature works. When DataGrid.ItemsSource changes in the first window, DataGrid.ItemsSource in the second window also changes.
Click on this link to view the image


I tested the following codes in different situations, using nearly the entire capacity of the MS Access database.

The conditions are as follows:

Number of records = 252,500

Database size = 2,094,128 KB (database size without any rows = 604 KB)

Size of each row = (Database size - database size without any rows) / Number of records => about 8.291184 KB (Of course, if I haven't made a mistake)

Hardware and software used in the test = Acer Aspire 5750G Laptop (Core i5 2nd Gen/4 GB RAM/Win7-x64), Visual Studio 2017, .NET Framework 4.5.2, WPF
XAML
<Window.Resources>
    <local:DatabaseDataSet x:Key="Database_DataSet"/>
    <CollectionViewSource x:Key="BookTableViewSource" Source="{Binding BookTable, Source={StaticResource Database_DataSet}}"/>
    <CollectionViewSource x:Key="MemberTableViewSource" Source="{Binding MemberTable, Source={StaticResource Database_DataSet}}"/>
</Window.Resources>
<Grid DataContext="{StaticResource BookTableViewSource}" Width="486" Height="386">
    <DataGrid x:Name="BookDataGrid" HeadersVisibility="Column" EnableRowVirtualization="True" VirtualizingPanel.ScrollUnit="Pixel" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="486" Height="386" Margin="0">
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="BookName" Binding="{Binding BookName}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Publisher" Binding="{Binding Publisher}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Category" Binding="{Binding Category}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="BookCode" Binding="{Binding BookCode}" IsReadOnly="True" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Inventory" Binding="{Binding Inventory}" IsReadOnly="True" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ReleaseDate" Binding="{Binding ReleaseDate}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="DateTaken" Binding="{Binding DateTaken}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ReturnDate" Binding="{Binding ReturnDate}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="RecipientName" Binding="{Binding RecipientName}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Language" Binding="{Binding BookLanguage}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Length" Binding="{Binding Length}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Form" Binding="{Binding Form}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Translator" Binding="{Binding Translator}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Narrator" Binding="{Binding Narrator}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="ISBN" Binding="{Binding ISBN}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Location" Binding="{Binding Location}" Width="SizeToHeader"/>
            <DataGridTextColumn x:Name="Price" Binding="{Binding Price}" Width="SizeToHeader"/>
            <DataGridTemplateColumn x:Name="BookImage" Width="SizeToHeader">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image x:Name="BookImg" Source="{Binding BookImage}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

C#
public DataView BDV = new DataView();
object[] BookCodeSelectedItems = null;
object[] ISBN_Value = null;
public MainWindow()
{
    InitializeComponent();
    BDV = BookDataGrid.ItemsSource as DataView; //In "XAML" or "C#," binding is only necessary once
}
private void DataGridDeleteMenu_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    switch (BookDataGrid.SelectedItems.Count > 0)
    {
        case false:
            MessageWindow MW = new MessageWindow();
            MW.YesButton.Visibility = Visibility.Hidden;
            MW.NoButton.Visibility = Visibility.Hidden;
            MW.MessageLabel.Margin = new Thickness(0, 110, 0, 0);
            MW.MessageLabel.HorizontalAlignment = HorizontalAlignment.Center;
            MW.Image.Source = GetImageFromBytes(System.IO.File.ReadAllBytes(System.Windows.Forms.Application.StartupPath + @"\Images\Warning.bin"));
            MW.MessageTextBlock.Text = "No rows selected";
            MW.OKButton.Content = "OK";
            MW.ShowDialog();
            break;
        default:
            var stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();
            List<object> Row = new List<object>();
            //Additionally, I tested the "AddRange" function of the "List<>" and it appeared to be one second slower. I mean "Row.AddRange(BookDataGrid.Items.Cast<object>().ToList());"
            for (int i = 0; i < BookDataGrid.Items.Count; i++)
            {
                Row.Add(BookDataGrid.Items[i]);
            }
            BookCodeSelectedItems = new object[BookDataGrid.SelectedItems.Count]; //I need this for further calculations
            ISBN_Value = new string[BookDataGrid.SelectedItems.Count]; //I need this for further calculations
            int j = 0;
            foreach (DataRowView DRV in BookDataGrid.SelectedItems)
            {
                BookCodeSelectedItems[j] = BDV.Table.Rows[BDV.Table.Rows.IndexOf(DRV.Row)][3];
                ISBN_Value[j] = BDV.Table.Rows[BDV.Table.Rows.IndexOf(DRV.Row)][14];
            }
            for (int i = 0; i < BookDataGrid.SelectedItems.Count; i++)
            {
                Row.Remove(BookDataGrid.SelectedItems[i]);
            }
            BookDataGrid.ItemsSource = Row;
            stopwatch.Stop();
            MessageBox.Show("Total seconds: " + stopwatch.Elapsed.TotalSeconds.ToString());
            break;
    }
}

Output:
Click this link to view the output

I also tried the following code, it was very slow. It took more than 10 minutes and I stopped the app. But List<> took about 16 seconds.
C#
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
for (int i = BookDataGrid.SelectedItems.Count - 1; i >= 0; i--)
{
    BDV.Table.Rows.Remove(((DataRowView)BookDataGrid.SelectedItems[i]).Row);
}
BookDataGrid.ItemsSource = BDV.Table.DefaultView;
stopwatch.Stop();
MessageBox.Show("Total seconds: " + stopwatch.Elapsed.TotalSeconds.ToString());

I hope this is the most comprehensive solution for converting DataGrid.ItemsSource to DataTable, DataView or another type of data source.
Thank you for your attention.
 
Share this answer
 
v7

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900