WPF DataGrid(双向)将单选按钮绑定到集合中Object的单个属性

时间:2014-06-17 19:18:08

标签: wpf vb.net xaml data-binding datagrid

我有一个数据类定义如下(为简洁起见缩短):

Partial Public Class ClassName
    Inherits ObservableCollection(Of MyObject)

    Public Event ItemPropertyChanged As PropertyChangedEventHandler

    Private Property _ContainsChanges As Boolean
    Public ReadOnly Property ContainsChanges As Boolean
        Get
            Return _ContainsChanges
        End Get
    End Property

    Protected Overridable Sub Notify_PropertyChanged(ByVal PropertyName As String)
        MyBase.OnPropertyChanged(New PropertyChangedEventArgs(PropertyName))
    End Sub

    Protected Overridable Sub Notify_ItemPropertyChanged(ByVal e As PropertyChangedEventArgs)
        RaiseEvent ItemPropertyChanged(Me, e)
    End Sub

    Protected Overridable Sub Me_PropertyChanged(ByVal sender As Object, e As PropertyChangedEventArgs) Handles Me.PropertyChanged
        Me._ContainsChanges = True
    End Sub

    Protected Overridable Sub Me_CollectionChanged(Sender As Object, e As NotifyCollectionChangedEventArgs) Handles Me.CollectionChanged
        If e.Action = NotifyCollectionChangedAction.Add Then
            For Each item As Account In e.NewItems
                AddHandler item.PropertyChanged, AddressOf Account_PropertyChanged
            Next
        ElseIf e.Action = NotifyCollectionChangedAction.Remove Then
            For Each item As Account In e.OldItems
                RemoveHandler item.PropertyChanged, AddressOf Account_PropertyChanged
            Next
        End If
    End Sub

    Protected Overridable Sub MyObject_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
        Me._ContainsChanges = True
        Notify_ItemPropertyChanged(e)
    End Sub

    Partial Public Class MyObject
        Implements INotifyPropertyChanged

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Private Property _ContainsChanges As Boolean
        Public ReadOnly Property ContainsChanges As Boolean
            Get
                Return _ContainsChanges
            End Get
        End Property

        Private Property _IntegerProperty As Integer
        Public Property IntegerProperty As Integer
            Get
                Return _IntegerProperty
            End Get
            Set(value As Integer)
                If value <> _IntegerPropertyThen
                    _IntegerProperty= value
                    Notify_PropertyChanged("IntegerProperty")
                End If
            End Set
        End Property

        Private Property _BooleanProperty As Nullable(Of Boolean)
        Public Property BooleanProperty As Nullable(Of Boolean)
            Get
                Return _BooleanProperty 
            End Get
            Set(value As Boolean)
                If value <> _BooleanProperty  Then
                    _BooleanProperty = value
                    Notify_PropertyChanged("BooleanProperty ")
                End If
            End Set
        End Property

        Private Sub Notify_PropertyChanged(ByVal PropertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyName))
        End Sub

        Protected Overridable Sub Me_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Handles Me.PropertyChanged
            Me._ContainsChanges = True
        End Sub
    End Class
End Class

此集合绑定到WPF用户控件,其中datagrid是其唯一元素。集合中的每个对象都由datagrid中的一行表示。 XAML如下所示:

<UserControl 
             x:Class="WPFControlNameSpace.WPFControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:converters="clr-namespace:WPFControlLibrary.WPFControlNameSpace.Converters"
             DataContext="{Binding DataGrid}">
    <UserControl.Resources>
        <converters:BooleanConverter x:Key="BooleanConverter"/>
        <Style TargetType="{x:Type DataGridColumnHeader}" x:Key="dgHeaderStyle">
            <Setter Property="Background" Value="Beige" />
            <Setter Property="Height" Value="30" />
            <Setter Property="FontSize" Value="15" />
            <Setter Property="BorderBrush" Value="Black" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="BorderThickness" Value=".5" />
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="FontFamily" Value="Arial" />
        </Style>
        <Style TargetType="{x:Type DataGrid}" x:Key="dgStyle">
            <Setter Property="AlternatingRowBackground" Value="Beige" />
            <Setter Property="AutoGenerateColumns" Value="False" />
            <Setter Property="CanUserAddRows" Value="False" />
            <Setter Property="CanUserDeleteRows" Value="False" />
            <Setter Property="FontSize" Value="13" />
            <Setter Property="MinColumnWidth" Value="30" />
        </Style>
    </UserControl.Resources>
    <DataGrid x:Name="dgClassName" 
              ItemsSource="{Binding}"
              ColumnHeaderStyle ="{StaticResource dgHeaderStyle}"
              Style="{StaticResource dgStyle}" 
              RowDetailsVisibilityMode="Collapsed"
              HeadersVisibility="Column"
              FontFamily="Arial">
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding lActive}" Value="True">
                        <Setter Property="ToolTip" Value="This row is Active!" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding lActive}" Value="False">
                        <Setter Property="ToolTip" Value="This row is Inactive!" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Foreground" Value="Black" />
                        <Setter Property="Background" Value="{x:Null}" />
                        <Setter Property="BorderBrush" Value="{x:Null}" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGrid.CellStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header=" Account Number " Binding="{Binding nAccountNumber}" IsReadOnly="True" MinWidth="50"/>
            <DataGridTextColumn Header=" Account Description " Binding="{Binding cAccountDescription}" IsReadOnly="True" MinWidth="50"/>
            <DataGridTemplateColumn Header=" Verified ">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Grid.Row="1" Orientation="Horizontal">
                            <RadioButton Content="Yes"
                                         IsChecked="{Binding BooleanProperty,
                                                     Converter={StaticResource BooleanConverter},
                                                     ConverterParameter='True', Mode=TwoWay}" />
                            <RadioButton Content="No"
                                         IsChecked="{Binding BooleanProperty,
                                                     Converter={StaticResource BooleanConverter},
                                                     ConverterParameter='False', Mode=TwoWay}" />
                            <RadioButton Content="Unknown"
                                         IsChecked="{Binding BooleanProperty,
                                                     Converter={StaticResource BooleanConverter},
                                                     ConverterParameter='Nothing', Mode=TwoWay}" />
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

        </DataGrid.Columns>
    </DataGrid>
</UserControl>

我使用的转换如下所示:

Namespace SungardVerification.Converters
    Class BooleanConverter
        Implements IValueConverter
        Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
            Dim SourceValue = CType(value, System.Nullable(Of Boolean))
            Dim RadioButtonCheckedValue As Nullable(Of Boolean) = Nothing

            If DirectCast(parameter, String).ToUpper.Trim() <> "NOTHING" Then
                RadioButtonCheckedValue = Boolean.Parse(DirectCast(parameter, String))
            End If

            If (RadioButtonCheckedValue.HasValue AndAlso SourceValue.HasValue AndAlso RadioButtonCheckedValue.Value = SourceValue.Value) OrElse
                (Not RadioButtonCheckedValue.HasValue AndAlso Not SourceValue.HasValue) Then
                Return True
            Else
                Return False
            End If
        End Function

        Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
            Dim RadioButtonChecked = CType(value, Boolean)
            Dim RadioButtonCheckedValue As Nullable(Of Boolean) = Nothing
            Dim SourceValue As Nullable(Of Boolean) = Nothing

            If RadioButtonChecked = True Then
                If DirectCast(parameter, String).ToUpper.Trim() <> "NOTHING" Then
                    SourceValue = Boolean.Parse(DirectCast(parameter, String))
                End If
                Return SourceValue
            Else
                Return Binding.DoNothing
            End If
        End Function
    End Class
End Namespace

此控件存在于用户控件库中,并使用元素主机包含在Windows窗体中。

datagrid正确地将集合中的值绑定到单元格,但是此绑定的双向方面无法正常工作。

我知道这可以通过一个不确定的复选框来完成,但是单选按钮对于用户选择的含义更清楚。

有没有人对如何使这项工作有任何建议?

1 个答案:

答案 0 :(得分:0)

没有注意到正确的行为,因为UpdateSourceTrigger属性保留为默认值。将XAML更改为以下内容可以解决我的问题。

<RadioButton Content="Unknown"
             IsChecked="{Binding BooleanProperty,
                         Converter={StaticResource BooleanConverter},
                         ConverterParameter='Nothing', Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />