0
votes

I'm using Ninject in an MVVM application which contains a Xceed PropertyGrid. The PropertyGrid should use a custom ItemSource for one particular property currently defined with an Attribute:

[ItemSource(GetType(SomeObjectItemSource)] 

The SomeObjectItemSource.GetValues would look like that and need's access to an object created with Ninject

Public Function GetValues() As ItemCollection Implements IItemsSource.GetValues

    Fetch RootObject from Ninject Kernel
    Extract a list of SomeObject from RootObject and Return

End Function

As the PropertyGrid is not created by Ninject and Ninject internally uses Activator.CreateInstance without any optional constructor parameters this approach fails as I cannot pass a reference to the Ninject kernel or to RootObject.

Note: The source of the PropertyGrid looks like this. Activate.CreateInstance would be able to use the constructor, but it isn't implemented that way.

private System.Collections.IEnumerable CreateItemsSource()
{
  var instance = Activator.CreateInstance( _attribute.Type );
  return ( instance as IItemsSource ).GetValues();
}

Alternatively it would be possible to use a custom type editor using ITypeEditor and binding the editor to a property of the instance which created the PropertyGrid. The approach is suggested here: http://wpftoolkit.codeplex.com/discussions/351513 and looks like:

Public Class SomeObjectTypeEditor
  Implements ITypeEditor
  Public Function ResolveEditor(propertyItem As PropertyItem) As FrameworkElement
    Dim box As New ComboBox() With { _
     .DisplayMemberPath = "SomeObject" _
    }

    Dim itemSourcebinding = New Binding("") With { _
        .Source = MainWindow.ListOfSomeObject , _
        .ValidatesOnExceptions = True, _
        .ValidatesOnDataErrors = True, _
        .Mode = BindingMode.OneWay _
    }
  End Function
End Class

If I want to stick to avoiding code behind I the only feasible way I see is using property injection on MainWindow.ListOfSomeObject. However this does not look right to me.

I also guess that such situations will arise with different controls as well. Is there a common, abstract approach on solving such issues for all WPF controls?

1

1 Answers

1
votes

The cleanest solution I found is to use a editing template and bind to a property of the ViewModel.

<xctk:EditorTemplateDefinition.EditingTemplate>
    <DataTemplate>
        <ComboBox Name="Combo" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ListOfSomeObject}"
                                             DisplayMemberPath="ObjectName"
                                             SelectedValuePath="ObjectID" />
    </DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>

Using this approach ListOfSomeObject can be created using property injection or directly with constructor injection.