1
votes

I am trying to allow a user to choose one of two format types for inputting double values, and then I want to use a DataTrigger in xaml to choose one of two separate control types for the user to input these values, based on the format they have chosen.

I have a view and a viewmodel. The view model has properties like this:

public class MyViewModel
{
    public string DoubleFormat {get;set;}
    public double X {get;set;}
    public double Y {get;set;}
    public double Z {get;set;}
}

The application will set the DoubleFormat property to something like "FormatA" or "FormatB" for the DataTrigger to trigger off of.

The xaml for my view looks like this:

 <DataTemplate x:Key="FormatAEditTemplate" DataType="common:MyViewModel">
     <util:FormatAEditorControl Value="{Binding X}"/>
  </DataTemplate>

  <DataTemplate x:Key="FormatBEditTemplate" DataType="common:MyViewModel">
     <wpftk:DecimalUpDown Value="{Binding X}" />
  </DataTemplate>

  <DataTemplate x:Key="MyEditTemplate" DataType="common:MyViewModel">
     <ContentControl x:Name="MyDoubleInputControl" />
     <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding DoubleFormat}" Value="FormatA">
           <Setter TargetName="MyDoubleInputControl" Property="ContentTemplate" Value="    
             {StaticResource FormatAEditTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding DoubleFormat}" Value="FormatB">
           <Setter TargetName="MyDoubleInputControl" Property="ContentTemplate" Value="
             {StaticResource FormatBEditTemplate}" />
        </DataTrigger>
     </DataTemplate.Triggers>
  </DataTemplate>

So in the trigger I'm essentially trying to set the ContentControl's ContentTemplate property to equal either of the two template values at the top, rendering either a util:FormatAEditorControl or a wpftk:DecimalUpDown for the user to edit the double value for the property X on the viewmodel.

The trigger does work and the correct control type is rendered, however the databinding of the input controls themselves does not work. The controls are rendered but with no "0.0" default value for the double property, nor does updating the property in the U/I affect the viewmodel property value. I also get the following output in the Output window when I turn on tons of WPF output logging:

System.Windows.Data Information: 41 : BindingExpression path error: 'X' property not found for 'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1') System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1') System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1') System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=X; DataItem=null; target element is 'DecimalUpDown' (Name='FooBar'); target property is 'Value' (type 'Nullable1')

... along with several other lines which seem to state essentially the same thing.

I can simply choose one of the two Control types to "hard code" into the xaml in place of the data trigger, and the databinding works properly, which leads me to suspect that setting the Binding property of the DataTrigger is interfering with the DataContext of the "child" Elements which are chosen by the trigger.

So then my question is, since I basically want every last thing in this entire view to have MyViewModel as its DataContext, is there any good way to have my DataTrigger choose either of the double input control types without interfering with their DataContexts? Or if I am fundamentally misunderstanding this scenario, then perhaps someone could just throw me a bone.

A gracious coworker managed to work around this situation by binding like this: {Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.X} but this seems like a fairly circuitous workaround.

Thank you!

1

1 Answers

1
votes

You are using a ContentControl, so the templated content is inherently referring to its Content property. From what you written above, that property is not set, hence the binding fault.

Try to set the ContentControl as:

 <DataTemplate x:Key="MyEditTemplate" DataType="common:MyViewModel">
     <ContentControl x:Name="MyDoubleInputControl" Content="{Binding}" />

  ...

 </DataTemplate>