raykendo
raykendo

Reputation: 640

No binding to IValueConverter DependencyProperty Occuring

For my WPF Datagrid, I'm using an IValueConverter that inherits DependencyObject, so I can add extra parameters. The problem is that my converter is not being notified that its parameters have changed. When the convert function runs, the properties are the default values.

Here's some of the code. Note that Property names have been changed to protect the innocent.

XAML:

<UserControl x:Class="UselessTool"
             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:my="clr-namespace:Lots.Of.Useless.Stuff"
             x:Name="Myself">
  <Grid x:Name="LayoutRoot">
    <Grid.Resources>
      <my:InvasiveWeightConverter x:Key="TotalWeightConverter"
                                  Department="{Binding Department, ElementName=Myself}" />
    </Grid.Resources>
    <DataGrid x:Name="BuildingGrid"
              ItemsSource="{Binding BuildingData, ElementName=Myself}">
      <DataGrid.Columns>
        <DataGridTextColumn Header="Building"
                            Binding="{Binding Building}" />
        <DataGridTextColumn Header="Room"
                            Binding="{Binding Room}" />
        <DataGridTextColumn Header="Fire Escapes"
                            Binding="{Binding FireEscapes}" />
        <DataGridTextColumn Header="Total Personnel Weight"
                            Binding="{Binding Room, Converter={StaticResource TotalWeightConverter}, Mode=TwoWay}" />
      </DataGrid.Columns>
    </DataGrid>
  </Grid>
</UserControl>

Code behind (VB.NET):

Imports System.Data
Imports System.ComponentModel
Public Class UselessTool
  Implements INotifyPropertyChanged

  Public Sub New()
    Me.Department = ""
    Me.BuildingData = New DataTable
  End Sub

  Public Sub ImportTables(BuildingTable as DataTable, department as String)
     Me.Department = department
     Me.BuildingData = BuildingTable.Select("[Department] = " & department).CopyToDataTable()
  End Sub

  Private _dept as String
  Public Property Department() as String
    Get
      return _dept
    End Get
    Set(value as String)
      _dept = value
      RaisePropertyChanged("Department")
    End Set
  End Property
  ....
End Class

Public Class InvasiveWeightConverter
  Inherits DependencyObject
  Implements IValueConverter

  Public Shared ReadOnly DepartmentProperty As DependencyProperty = DependencyProperty.Register("Department", GetType(String), GetType(InvasiveWeightConverter), New PropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf DPChangeHandler)))

  Public Property Department() As String
      Get
          Return DirectCast(GetValue(DepartmentProperty), String)
      End Get
      Set(value As String)
          SetValue(DepartmentProperty, value)
      End Set
  End Property

  Private Shared Sub DPChangeHandler(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
    MsgBox(e.NewValue.ToString)
    ' the part above is not being fired
  End Sub

  Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
    Dim room As String = CType(value, String)

    Dim dataTable As DataTable = Personnel_Table
    Dim clause As String = String.Format("[{0}] = '{1}' AND [{2}] = '{3}'", dataTable.DepartmentColumn.ToString, Department, dataTable.RoomColumn.ToString, room)
    ' this is where I notice that Department is empty
    Dim rows() As DataRow = dataTable.Select(clause, "", DataViewRowState.CurrentRows)

    Dim totalWeight As Integer
    Dim weight As Integer
    For Each row In rows
        weight = CInt(row.Item("Weight"))
        totalWeight += weight 
    Next
    Return totalWeight 

  End Function

  Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
    Return Nothing
  End Function

End Class

Upvotes: 0

Views: 1691

Answers (2)

Smotsch
Smotsch

Reputation: 119

The easiest way to pass more than one parameter to a converter is to use MultiBinding

C#

public class TotalWeightConverter : IMultiValueConverter
{
    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        ResultType result;
        var room =(RoomType)value[0];
        var department = (DepartmentType)value[1];

        // Do something
        return result;
    }

    public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        // Do somethig
        return new object[2];
    }
}

XAML:

<DataGridTextColumn Header="Total Personnel Weight">
    <DataGridTextColumn.Binding>
        <MultiBinding Converter={StaticResource TotalWeightConverter}>
            <Binding Path="Room" />
            <Binding Path="Department" Mode="OneWay"/>
        </MultiBinding>
    </DataGridTextColumn>
</DataGridTextColumn>

But the best way is descriped by HighCore

Upvotes: 0

eran otzap
eran otzap

Reputation: 12533

Inherit from Freezable , as i understand it , it delays the binding so you can use the object as a resource .

Upvotes: 1

Related Questions