1

I have defined on my ViewModel class a static property named

static member GetColumnTypes = FSharpType.GetUnionCases typeof<ColumnType>

where ColumnType is a normal union type

type ColumnType   = T_Link of TableName | T_Real | T_Bool | T_Int | T_String

I don't understand the logic at play in XAML to bind to such a collection in the following scenarios :

<UserControl.Resources>
  <ObjectDataProvider x:Key="typelist" MethodName="GetColumnTypes" ObjectType="{x:Type local:MarkupViewModel}"/>
  <local:MarkupViewModel x:Key="defaultVM" d:IsDataSource="True"/>
</UserControl.Resources>

  //1-WORKS
  <ComboBox ItemsSource="{Binding Source={StaticResource defaultVM}, Path=GetColumnTypes}"></ComboBox> 

  //2-DOES NOT WORK
  <ComboBox ItemsSource="{Binding Source={StaticResource typelist}}"></ComboBox>

  //3-DOES NOT WORK
  <ComboBox ItemsSource="{Binding Source={x:Type local:MarkupViewModel}, Path=GetColumnTypes}"></ComboBox>

  //4-WORKS
  <ComboBox ItemsSource="{Binding  Path=GetColumnTypes}" />
  1. Why does this work ? I though the static ressource named defaultVM was creating an object using the parameterless constructor. On this object, there is no method GetColumnTypes !
  2. Why does it not work ? I thought I was calling GetColumnTypes on the type specified. and if I look at example getting Enum values, it seems to be what is happening. my case is jsut simpler as it has no parameters
  3. Again, does this not call he method on the mentionned type ?
  4. Here I set the datacontext to an instance of my Viremodel, and it 'magically' knows hos to go from the instance to a static method.

Beside those questions, I feel like it is very much black box magic, and I see very little information about the binding process.

What is the best approach to make it clear ?
Are there may be some debugging tool available for the Binding process ?

Community
  • 1
  • 1
nicolas
  • 9,549
  • 3
  • 39
  • 83

1 Answers1

3

There are two things to know that should clear things up:

First, in XAML, you can access static members through an instance of the type. You can also do this in VB.NET, for instance with this code:

Dim x = New MarkupViewModel()
x.GetColumnTypes
MarkupViewModel.GetColumnTypes

The last two lines are equivalent. In fact, the compiler rewrites the first line as the second. XAML is the same way. If you have an instance, you can access a static member through the same syntax as an instance member. (Other languages, like C# and F#, don't allow this syntax).

Second, ObjectDataProvider calls a method, but GetColumnTypes is a property. If you had defined it as static member GetColumnTypes() = ... I would expect it to work.

However, none of these approaches are really ideal. What you want to do is use the x:Static markup extension. This is what it was designed for.

In your namespace definitions (in the topmost tag of the XAML file), write something like this:

<UserControl [...] xmlns:local="clr-namespace:Your.Namespace">

And then have the combo box declare its items like this:

<ComboBox ItemsSource="{x:Static local:MarkupViewModel.GetColumnTypes}">

(although if you're keeping it as a property and not a function you should of course rename it as ColumnTypes not GetColumnTypes)

Oh, and as for diagnosing binding errors, quite a lot of debugging information is available through Visual Studio Options > Debugging > Output Window > WPF Trace Settings, which can dump a lot of information to the output window. However they can be somewhat difficult to interpret if you don't know WPF very well. An excellent general-purpose WPF utility is Snoop, which is good for many other reasons, but it can also display binding error information.

Jacob
  • 1,699
  • 10
  • 11
  • I realized a few things when going away from the problem a bit, like the static thing. I already use snoop but did not realize it could show bindings traces. This is all very helpful, thank you. – nicolas Mar 28 '13 at 09:17
  • The C# static rewriting seems wrong though. for instance : var a = (new DateTime()).Now; => Error 2 Member 'System.DateTime.Now.get' cannot be accessed with an instance reference; qualify it with a type name instead – nicolas Mar 28 '13 at 09:19
  • Oops, you are right. I was tired and mixed up which language supports that syntax (it's a 'feature' that leads to programming errors so I don't really think about it that often). It's VB.NET where those lines are equivalent (also Java and probably a few others). I'll fix my answer. – Jacob Mar 28 '13 at 12:57