views:

203

answers:

1

I'm using a viewmodel pattern, so my DataContext for my custom user control is actually a viewmodel wrapper for the real data.

My custom control can contain hierarchal instances of the custom control.

I set up a DependencyProperty in the custom control for the real piece of data, with the hopes of creating a new viewmodel for that data when it gets set via binding, and then setting the user control's datacontext to the new viewmodel. However, it seems that setting the DataContext property causes my real data DependencyProperty to become invalidated and set to null. Anyone know a way around this, or rather a proper way I should be using viewmodels?

Trimmed samples of what I'm trying to do:

The user control:

public partial class ArchetypeControl : UserControl
{
    public static readonly DependencyProperty ArchetypeProperty = DependencyProperty.Register(
      "Archetype",
      typeof(Archetype),
      typeof(ArchetypeControl),
      new PropertyMetadata(null, OnArchetypeChanged)
    );

    ArchetypeViewModel _viewModel;

    public Archetype Archetype
    {
        get { return (Archetype)GetValue(ArchetypeProperty); }
        set { SetValue(ArchetypeProperty, value); }
    }

    private void InitFromArchetype(Archetype newArchetype)
    {
        if (_viewModel != null)
        {
            _viewModel.Destroy();
            _viewModel = null;
        }

        if (newArchetype != null)
        {
            _viewModel = new ArchetypeViewModel(newArchetype);

            // calling this results in OnArchetypeChanged getting called again
            // with new value of null!
            DataContext = _viewModel;
        }
    }

    // the first time this is called, its with a good NewValue.
    // the second time (after setting DataContext), NewValue is null.
    static void OnArchetypeChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args )
    {
        var control = (ArchetypeControl)obj;

        control.InitFromArchetype(args.NewValue as Archetype);
    }
}

The viewmodel:

class ArchetypeComplexPropertyViewModel : ArchetypePropertyViewModel
{
    public Archetype Value { get { return Property.ArchetypeValue; } }
}

The XAML:

<Style TargetType="{x:Type TreeViewItem}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ViewModelType}" Value="{x:Type c:ArchetypeComplexPropertyViewModel}">
                <Setter Property="Template" Value="{StaticResource ComplexPropertyTemplate}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

<ControlTemplate x:Key="ComplexPropertyTemplate" TargetType="{x:Type TreeViewItem}">
        <Grid>
            <c:ArchetypeControl Archetype="{Binding Value}" />
        </Grid>
    </ControlTemplate>

This problem was mentioned in the comments of http://stackoverflow.com/questions/1566463/cannot-databind-dependencyproperty but never resolved

A: 

By doing this:

<c:ArchetypeControl Archetype="{Binding Value}" />

You are binding your Archetype property to the property called Value on your data context. By changing your data context to the new ArchetypeViewModel you effectively cause a new evaluation of the binding. You need to make sure that the new ArchetypeViewModel object has a non-null Value property.

Without seeing the more of your code (specifically, the definitions of ArchetypeComplexPropertyViewModel and ArchetypePropertyViewModel) I can't really say what is the cause of this.

Aviad P.