wpf ,datagrid row has inner datagrid,select cell problem

建军 刘 21 Reputation points
2020-06-24T03:42:34.453+00:00

One datagrid ,each row has one detail datagrid, i want to select cell outter datagrid and inner datagrid same time,but it's failed.when select cell in inner datagrid,the outer datagird cell selected will unselect,how to select cell outter datagrid and inner datagrid same time?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,709 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,311 Reputation points
    2020-06-24T05:08:15.377+00:00

    Hi, there can only be one active, selected cell in a DataGrid. The current line in the outer DataGrid and in the inner DataGrid can be captured and processed. Try following demo:

    <Window x:Class="Window034"  
            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:WpfApp1.WpfApp034"  
            mc:Ignorable="d"  
            Title="Demo 75947307" Height="450" Width="800">  
      <Window.Resources>  
        <local:ViewModel x:Key="vm"/>  
      </Window.Resources>  
      <Grid DataContext="{StaticResource vm}">  
        <Grid.RowDefinitions>  
          <RowDefinition/>  
          <RowDefinition Height="Auto"/>  
        </Grid.RowDefinitions>  
        <DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False" IsReadOnly="True">  
          <DataGrid.Columns>  
            <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>  
            <DataGridTextColumn Header="Info" Binding="{Binding Info}"/>  
          </DataGrid.Columns>  
          <DataGrid.RowDetailsTemplate>  
            <DataTemplate>  
              <DataGrid ItemsSource="{Binding DetailView, Source={StaticResource vm}}" IsReadOnly="True"/>  
            </DataTemplate>  
          </DataGrid.RowDetailsTemplate>  
        </DataGrid>  
        <Label Grid.Row="1" Content="{Binding Log}"/>  
      </Grid>  
    </Window>  
    

    --------------------------------------------------------

    Imports System.Collections.ObjectModel  
    Imports System.ComponentModel  
    Imports System.Runtime.CompilerServices  
      
    Namespace WpfApp034  
      Public Class ViewModel  
        Implements INotifyPropertyChanged  
      
        Private cvs As New CollectionViewSource  
        Private col As New ObservableCollection(Of Data)  
        Public ReadOnly Property View As ICollectionView  
          Get  
            If cvs.Source Is Nothing Then  
              GetData()  
              AddHandler cvs.View.CurrentChanged, Sub()  
                                                    CurrentItem = TryCast(cvs.View.CurrentItem, Data)  
                                                  End Sub  
            End If  
            Return cvs.View  
          End Get  
        End Property  
      
        Private cvsDetail As New CollectionViewSource  
        Public ReadOnly Property DetailView As ICollectionView  
          Get  
            Return cvsDetail.View  
          End Get  
        End Property  
      
        Private _currentItem As Data  
        Public Property CurrentItem As Data  
          Get  
            Return Me._currentItem  
          End Get  
          Set(value As Data)  
            Me._currentItem = value  
            Me.cvsDetail.Source = value.Details  
            Log = $"Selected row: {value.ID}"  
            AddHandler cvsDetail.View.CurrentChanged, Sub()  
                                                        Dim detail = TryCast(cvsDetail.View.CurrentItem, DataDetail)  
                                                        Log = $"Selected row: {value.ID}, detail row: {detail.DetailInfo}"  
                                                      End Sub  
            OnPropertyChanged()  
          End Set  
        End Property  
      
        Private _log As String  
        Public Property Log As String  
          Get  
            Return Me._log  
          End Get  
          Set(value As String)  
            Me._log = value  
            OnPropertyChanged()  
          End Set  
        End Property  
      
        Private Sub GetData()  
          For i = 1 To 10  
            Dim d As New Data With {.ID = i, .Info = $"Row {i}"}  
            For k = 1 To 5  
              d.Details.Add(New DataDetail With {.DetailID = k, .DetailInfo = $"Detail row {i} - {k}"})  
            Next  
            col.Add(d)  
          Next  
          cvs.Source = col  
          CurrentItem = TryCast(cvs.View.CurrentItem, Data)  
        End Sub  
      
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged  
        Friend Sub OnPropertyChanged(<CallerMemberName> Optional propName As String = "")  
          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))  
        End Sub  
      End Class  
      
      Public Class Data  
        Public Property ID As Integer  
        Public Property Info As String  
        Public Property Details As New ObservableCollection(Of DataDetail)  
      End Class  
      
      Public Class DataDetail  
        Public Property DetailID As Integer  
        Public Property DetailInfo As String  
      End Class  
      
    End Namespace  
    

    10547-24-06-2020-07-01-42.gif

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,311 Reputation points
    2020-06-24T06:48:13.337+00:00

    Hi, the same project in C#.NET:

    <Window x:Class="WpfApp1.Window50"
            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:WpfApp50"
            mc:Ignorable="d"
           Title="Demo 75947307" Height="450" Width="800">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False" IsReadOnly="True">
          <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
            <DataGridTextColumn Header="Info" Binding="{Binding Info}"/>
          </DataGrid.Columns>
          <DataGrid.RowDetailsTemplate>
            <DataTemplate>
              <DataGrid ItemsSource="{Binding DetailView, Source={StaticResource vm}}" IsReadOnly="True"/>
            </DataTemplate>
          </DataGrid.RowDetailsTemplate>
        </DataGrid>
        <Label Grid.Row="1" Content="{Binding Log}"/>
      </Grid>
    </Window>
    

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp50
    {
      public class ViewModel : INotifyPropertyChanged
      {
        private CollectionViewSource cvs = new CollectionViewSource();
        private ObservableCollection<Data> col = new ObservableCollection<Data>();
        public ICollectionView View
        {
          get
          {
            if (cvs.Source == null)
            {
              GetData();
              cvs.View.CurrentChanged += (sender, e) => CurrentItem = cvs.View.CurrentItem as Data;
            }
            return cvs.View;
          }
        }
    
        private CollectionViewSource cvsDetail = new CollectionViewSource();
        public ICollectionView DetailView { get => cvsDetail.View; }
    
        private Data _currentItem;
        public Data CurrentItem
        {
          get => this._currentItem;
          set
          {
            this._currentItem = value;
            this.cvsDetail.Source = value.Details;
            Log = $"Selected row: {value.ID}";
            cvsDetail.View.CurrentChanged += (sender, e) =>
            {
              var detail = cvsDetail.View.CurrentItem as DataDetail;
              Log = $"Selected row: {value.ID}, detail row: {detail.DetailInfo}";
            };
            OnPropertyChanged();
          }
        }
    
        private string _log;
        public string Log
        {
          get => this._log;
          set
          {
            this._log = value;
            OnPropertyChanged();
          }
        }
    
        private void GetData()
        {
          for (int i = 1; i < 11; i++)
          {
            var d = new Data { ID = i, Info = $"Row {i}" };
            for (int k = 1; k < 6; k++) d.Details.Add(new DataDetail { DetailID = k, DetailInfo = $"Detail row {i} - {k}" });
            col.Add(d);
          }
          cvs.Source = col;
          CurrentItem = cvs.View.CurrentItem as Data;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] String propertyName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      public class Data
      {
        public int ID { get; set; }
        public string Info { get; set; }
        public ObservableCollection<DataDetail> Details { get; } = new ObservableCollection<DataDetail>();
      }
    
      public class DataDetail
      {
        public int DetailID { get; set; }
        public string DetailInfo { get; set; }
      }
    }
    
    1 person found this answer helpful.