none
Wie kann man bei einem WPF Datagrid beim Selektieren einer Zeile die anderen Zeilen ausblenden? RRS feed

  • Frage

  • Hallo zusammen,

    ich habe ein WPF-Datagrid, welches an eine CollectionViewSource "_dataGridListViewSource" gebunden ist.

    im CodeBehind des UserControls:
    private CollectionViewSource _dataGridListViewSource;
    _dataGridListViewSource = FindResource("dataGridListViewSource") as CollectionViewSource;

    Im XAML des UserControls

    <CollectionViewSource x:Key="DataGridListViewSource" 
                                  Source="{Binding AngemeldeterBenutzer.Benutzer}"
                                  Filter="DataGridCollectionViewSource_Filter"/>
    
    
    <DataGrid Name="dataGridÜbersicht" 
                                              ItemsSource="{Binding Source={StaticResource DataGridListViewSource}}"
                                              SelectedValuePath="BenutzerID"
                                              SelectionChanged="dataGrid_SelectionChanged"
                                              Style="{DynamicResource DataGridStyleBenutzer}">
    
    <DataGrid.RowHeaderTemplate>
                                            <DataTemplate>
                                                <Grid>
                                                    <CheckBox x:Name="benutzerRowSelectedCheckBox" 
                                                              IsChecked="{Binding IsSelected, Mode=TwoWay, 
                                                              RelativeSource={RelativeSource AncestorType=DataGridRow} }" />
                                                </Grid>
                                            </DataTemplate>
                                        </DataGrid.RowHeaderTemplate

    Zu der CollectionViewSource habe ich schon eine Filter-Methode, die an ein TextBox-Steuerelement gebunden ist und die Datensätze nach dem TextBox.Text filtert, was auch funktioniert.

    In dem Datagrid möchte ich nun zusätzlich mit Hilfe des Events "SelectionChanged" im DataGrid und der Methode "dataGrid_SelectionChanged" alle Datensätze ausblenden außer dem gerade markierten Datensatz, weil dann ein weiteres Template, welches an den markierten Datensatz gebunden ist, angezeigt wird.

    Ich habe im RowHeaderTemplate Checkboxen eingebunden.

    Hat einer eine Idee, wie ich das bewerkstelligen kann?

    Gruß Jürgen

    Samstag, 13. August 2016 12:17

Antworten

  • Hi,
    wenn ich es jetzt richtig verstanden habe, dann sollen alle Zeilen sichtbar sein, wenn keine Zeile selektiert ist. Sobald eine Zeile selektiert ist, soll nur diese sichtbar sein. Dazu habe ich eine Demo erstellt:

    XAML:

    <Window x:Class="Window35"
            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:WpfApplication1VB"
            mc:Ignorable="d"
            Title="Window35" Height="300" Width="300">
      <Window.Resources>
        <local:Window35VM x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{Binding Source={StaticResource vm}}">
        <DataGrid ItemsSource="{Binding View}" 
                  AutoGenerateColumns="false"
                  IsReadOnly="true"
                  local:Window35VM.AttDataGrid="True">
          <DataGrid.Columns>
            <DataGridTextColumn Header="Info 1" Binding="{Binding Info1}"/>
          </DataGrid.Columns>
          <DataGrid.RowDetailsTemplate>
            <DataTemplate>
              <Label Content="{Binding Info2}"/>
            </DataTemplate>
          </DataGrid.RowDetailsTemplate>
          <DataGrid.RowHeaderTemplate>
            <DataTemplate>
              <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                      RelativeSource={RelativeSource FindAncestor,
                      AncestorType={x:Type DataGridRow}}}"/>
            </DataTemplate>
          </DataGrid.RowHeaderTemplate>
        </DataGrid>
      </Grid>
    </Window>

    ViewModel:

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    
    Public Class Window35VM
    
      Private cvs As CollectionViewSource
      Public ReadOnly Property View As ICollectionView
        Get
          If cvs Is Nothing Then
            cvs = New CollectionViewSource
            cvs.Source = GetData()
          End If
          Return cvs.View
        End Get
      End Property
    
      Private Function GetData() As Object
        Dim l As New ObservableCollection(Of Window35Data1)
        For i = 1 To 10
          l.Add(New Window35Data1 With {.Info1 = $"Zeile {i}", .Info2 = $"Ergänzungsinfo {i}"})
        Next
        Return l
      End Function
    
      Public Shared ReadOnly AttDataGridProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("AttDataGrid",
                                            GetType(Boolean),
                                            GetType(Window35VM),
                                            New UIPropertyMetadata(False, AddressOf OnAttDataGrid))
      Public Shared Function GetAttDataGrid(ByVal obj As DependencyObject) As Boolean
        Return CType(obj.GetValue(AttDataGridProperty), Boolean)
      End Function
      Public Shared Sub SetAttDataGrid(ByVal obj As DependencyObject, ByVal value As Boolean)
        obj.SetValue(AttDataGridProperty, value)
      End Sub
      Private Shared Sub OnAttDataGrid(ByVal depObj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim dg = TryCast(depObj, DataGrid)
        If dg Is Nothing Then Exit Sub
        If e.NewValue.GetType IsNot GetType(Boolean) Then Exit Sub
        If CType(e.NewValue, Boolean) Then
          AddHandler dg.SelectionChanged, AddressOf OnSelectionChanged
        Else
          RemoveHandler dg.SelectionChanged, AddressOf OnSelectionChanged
        End If
      End Sub
    
      Private Shared Sub OnSelectionChanged(sender As Object, e As SelectionChangedEventArgs)
        Dim dg = TryCast(sender, DataGrid)
        If dg Is Nothing Then Exit Sub
        For i = 0 To dg.Items.Count - 1
          Dim row = CType(dg.ItemContainerGenerator.ContainerFromIndex(i), DataGridRow)
          If Not row?.IsSelected Then row.Visibility = If(dg.SelectedItems.Count = 0, Visibility.Visible, Visibility.Collapsed)
        Next
      End Sub
    
    End Class
    
    Public Class Window35Data1
    
      Public Property Info1 As String
      Public Property Info2 As String
    
    End Class


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Warum Groß- und Kleinschreibung wichtig ist:
    Der Gefangene floh.
    Der gefangene Floh.

    Dienstag, 23. August 2016 20:20

Alle Antworten

  • Hallo Hallo,

    hat hier keiner eine Idee???

    Montag, 15. August 2016 13:15
  • Es gibt im DataGrid die Zeile SelectedIndex und SelectedItem. Beides kannst du binden. Wenn du diese Werte passend auswertest und deinem Filter hinzu fügst, sollte dein Filter am Schluss nur noch den gewünschten Datensatz liefern. Mir ist nur grade nicht sicher, was es mit dem Rowheader zu tun hat. 
    Dienstag, 23. August 2016 14:02
  • Hallo Uriel,

    ich kenne die Properties "SelectedIndex" und "SelectedItem"

    Dienstag, 23. August 2016 15:19
  • Hi Jürgen,
    Deine Frage ist mir persönlich unklar. Wenn alle weiteren Datensätze außer einem ausgeblendet werden, wie sollen dann diese wieder eingeblendet werden?

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Warum Groß- und Kleinschreibung wichtig ist:
    Der Gefangene floh.
    Der gefangene Floh.

    Dienstag, 23. August 2016 15:29
  • Hallo zusammen,

    wie man an dem obigen XAML-Schnipsel erkennen kann, habe ich im RowHeader ein DataTemplate mit einer Checkbox, die an die IsSelected-Property der DataGridRow gebunden ist.

    Deaktiviere ich die Checkbox, wird die DataGridRow Unselected.

    Sinn meines Wunsches ist, in einem Datagrid mit mehreren Hundert Datensätzen genau einen zu markieren und alle anderen Datensätze auszublenden, da zu dem Datensatz der RowDetailsBereich eingeblendet wird, der ebenfalls ein weiteres DataGrid mit mehreren Datensätzen beinhaltet.

    Der User soll sich also nur auf den markierten Datensatz mit den Details konzentrieren können. Daher sollen alle anderen Datensätze ausgeblendet werden. Wenn man dann die Checkbox im RowHeader wieder deaktiviert sollen die anderen Datensätze wieder eingeblendet werden.

    Gruß Jürgen

    Dienstag, 23. August 2016 17:09
  • Hi,
    wenn ich es jetzt richtig verstanden habe, dann sollen alle Zeilen sichtbar sein, wenn keine Zeile selektiert ist. Sobald eine Zeile selektiert ist, soll nur diese sichtbar sein. Dazu habe ich eine Demo erstellt:

    XAML:

    <Window x:Class="Window35"
            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:WpfApplication1VB"
            mc:Ignorable="d"
            Title="Window35" Height="300" Width="300">
      <Window.Resources>
        <local:Window35VM x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{Binding Source={StaticResource vm}}">
        <DataGrid ItemsSource="{Binding View}" 
                  AutoGenerateColumns="false"
                  IsReadOnly="true"
                  local:Window35VM.AttDataGrid="True">
          <DataGrid.Columns>
            <DataGridTextColumn Header="Info 1" Binding="{Binding Info1}"/>
          </DataGrid.Columns>
          <DataGrid.RowDetailsTemplate>
            <DataTemplate>
              <Label Content="{Binding Info2}"/>
            </DataTemplate>
          </DataGrid.RowDetailsTemplate>
          <DataGrid.RowHeaderTemplate>
            <DataTemplate>
              <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                      RelativeSource={RelativeSource FindAncestor,
                      AncestorType={x:Type DataGridRow}}}"/>
            </DataTemplate>
          </DataGrid.RowHeaderTemplate>
        </DataGrid>
      </Grid>
    </Window>

    ViewModel:

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    
    Public Class Window35VM
    
      Private cvs As CollectionViewSource
      Public ReadOnly Property View As ICollectionView
        Get
          If cvs Is Nothing Then
            cvs = New CollectionViewSource
            cvs.Source = GetData()
          End If
          Return cvs.View
        End Get
      End Property
    
      Private Function GetData() As Object
        Dim l As New ObservableCollection(Of Window35Data1)
        For i = 1 To 10
          l.Add(New Window35Data1 With {.Info1 = $"Zeile {i}", .Info2 = $"Ergänzungsinfo {i}"})
        Next
        Return l
      End Function
    
      Public Shared ReadOnly AttDataGridProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("AttDataGrid",
                                            GetType(Boolean),
                                            GetType(Window35VM),
                                            New UIPropertyMetadata(False, AddressOf OnAttDataGrid))
      Public Shared Function GetAttDataGrid(ByVal obj As DependencyObject) As Boolean
        Return CType(obj.GetValue(AttDataGridProperty), Boolean)
      End Function
      Public Shared Sub SetAttDataGrid(ByVal obj As DependencyObject, ByVal value As Boolean)
        obj.SetValue(AttDataGridProperty, value)
      End Sub
      Private Shared Sub OnAttDataGrid(ByVal depObj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim dg = TryCast(depObj, DataGrid)
        If dg Is Nothing Then Exit Sub
        If e.NewValue.GetType IsNot GetType(Boolean) Then Exit Sub
        If CType(e.NewValue, Boolean) Then
          AddHandler dg.SelectionChanged, AddressOf OnSelectionChanged
        Else
          RemoveHandler dg.SelectionChanged, AddressOf OnSelectionChanged
        End If
      End Sub
    
      Private Shared Sub OnSelectionChanged(sender As Object, e As SelectionChangedEventArgs)
        Dim dg = TryCast(sender, DataGrid)
        If dg Is Nothing Then Exit Sub
        For i = 0 To dg.Items.Count - 1
          Dim row = CType(dg.ItemContainerGenerator.ContainerFromIndex(i), DataGridRow)
          If Not row?.IsSelected Then row.Visibility = If(dg.SelectedItems.Count = 0, Visibility.Visible, Visibility.Collapsed)
        Next
      End Sub
    
    End Class
    
    Public Class Window35Data1
    
      Public Property Info1 As String
      Public Property Info2 As String
    
    End Class


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Warum Groß- und Kleinschreibung wichtig ist:
    Der Gefangene floh.
    Der gefangene Floh.

    Dienstag, 23. August 2016 20:20