none
datagrid binding two way RRS feed

  • Frage

  • I have a wpf datagrid with a checkboxcolumn. In all rows only exactly one row should have this column checked (like a radiobutton)

    With NotifyOnTargetUpdated=True and adding a suitable handler, I get all clicks in these checkboxes. Works fine and I do the above "Radio button" Task on may rowdata, derived from (ObservableCollection). But I find no way to instantanously update the datagrid view, showing many checks instead. Binding from source to target doesnt work.

    Tried sucessless with INotifyPropertyChange interface and direct calling UpdateTarget. Can u post an very simple example solving my Problem. 

    Samstag, 25. Mai 2019 19:47

Antworten

  • Hi,
    nachfolgend mal eine MVVM-Demo zur Lösung Deines Problems. Wichtig ist, dass das Datenobjekt die Änderung des Checked-Zustandes per NotifyPropertyChanged meldet und die Collection diese Änderung auch weitermeldet. Dadurch können die Zustände in den anderen Datenobjekten rückgesetzt werden. Als Collection eignet sich eine von ObservableCollection abgeleitete Collection, die die Änderungen "fängt" und weitermeldet, im Beispiel die TrulyObservableCollection.

    XAML:

    <Window x:Class="Window33"
            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"
            mc:Ignorable="d"
            Title="Window33" Height="450" Width="800">
      <Window.DataContext>
        <local:Window33VM/>
      </Window.DataContext>
      <Grid>
        <DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
            <DataGridTextColumn Header="Info" Binding="{Binding Info}"/>
            <DataGridTemplateColumn Header="Checked">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <CheckBox IsChecked="{Binding Path=Checked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                            HorizontalAlignment="Center"/>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
      </Grid>
    </Window>
    

    Datenklassen:

    Imports System.Collections.Specialized
    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    
    Public Class Window33VM
    
      Private col As New TrulyObservableCollection(Of Window33Data)
      Private cvs As New CollectionViewSource
    
      ''' <summary>
      ''' View to display the list of items
      ''' </summary>
      ''' <returns></returns>
      Public ReadOnly Property View As ICollectionView
        Get
          If cvs.Source Is Nothing Then
            col = GetData()
            cvs.Source = col
            AddHandler col.CollectionChanged, Sub(sender As Object, e As NotifyCollectionChangedEventArgs)
                                                Dim d = TryCast(e.NewItems(0), Window33Data)
                                                If d IsNot cvs.View.CurrentItem Then Exit Sub
                                                If e.Action = NotifyCollectionChangedAction.Replace AndAlso d.Checked Then
                                                  For Each item In col
                                                    If item IsNot d AndAlso item.Checked Then item.Checked = False
                                                  Next
                                                End If
                                              End Sub
          End If
          Return cvs.View
        End Get
      End Property
    
      Private Function GetData() As TrulyObservableCollection(Of Window33Data)
        Dim col As New TrulyObservableCollection(Of Window33Data)
        For i = 1 To 10
          col.Add(New Window33Data With {.ID = i, .Info = $"Data {i}"})
        Next
        Return col
      End Function
    End Class
    
    Public Class Window33Data
      Implements INotifyPropertyChanged
      Public Property ID As Integer
      Public Property Info As String
    
      Private _checked As Boolean = False
      Public Property Checked As Boolean
        Get
          Return Me._checked
        End Get
        Set(value As Boolean)
          Me._checked = value
          OnPropChanged()
        End Set
      End Property
    
      Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      Private Sub OnPropChanged(<CallerMemberName> Optional propName As String = "")
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
      End Sub
    
    End Class


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Sonntag, 26. Mai 2019 05:26