views:

824

answers:

2

I have an application that uses MVVM. I have several items on the main window that bind to the ViewModel for that window. When I run it everything works. However, when I add a user control to the main window and try to bind to one of its dependency objects it throws an exception (“Object reference not set to an instance of an object”). The exception window just pops up on the screen and does not link to any particular place in code. And any other information in the exception is not helpful.

I’ve tried my best to trace this down but I’m not having any luck. In the constructor of window I’ve checked and verified that the item that it’s attempting to bind to exists and is an object (int[]). I’ve also manually set the property in the constructor with problems. Here are some code snippets if anyone can notice anything.

Here is where I use the user control and attempt to bind to the 'view' property

<local:Histogram Grid.Row="2" Grid.ColumnSpan="2"
                                        View="{Binding Path=HistogramData}"             
                                     Foreground="{DynamicResource FontColor}"
                                     BucketStroke="{DynamicResource BucketStrokeBrush}"
                                     BucketFill="{DynamicResource BucketFillBrush}"
                                     SelectedBrush="{DynamicResource FamilyEditListViewSelectedBrush}"
                                     DisabledForegroundBrush="{DynamicResource DisabledForegroundBrush}"
                                     AxisBrush="{DynamicResource AxisBrush}" 
                                        MaxHeight="130" />

Here is the field in the view model that I am attempting to bind to:

public int[] HistogramData
    {
        get
        {
            return histogramData;
        }
        set
        {
            if (value != histogramData)
            {
                histogramData = value;
                RaisePropertyChanged("HistogramData");
            }
        }
    }

And in the constructor of the view model I instantiate the object

histogramData = new int[256];

And finally here is the view property in the user control

public static readonly DependencyProperty ViewProperty =
        DependencyProperty.Register("View", 
                                    typeof(int[]), 
                                    typeof(Histogram),
                                    new FrameworkPropertyMetadata(null,
                                                                  FrameworkPropertyMetadataOptions.AffectsRender,
                                                                  new PropertyChangedCallback(ViewProperty_Changed)));

    public int[] View
    {
        get { return (int[])GetValue(ViewProperty); }
        set { SetValue(ViewProperty, value); }
    }

I don't know if this is enough information to solve anything so if more code is req please let me know. I could also zip up the project if someone is so inclined to look at that. Thanks in advance.

+1  A: 

Use the debugger to get an exception stack trace. That should help you narrow the problem down.

There are several ways to do this. For example, you should be able to just view the details of the exception. Or you could open a watch window and enter the expression $exception and then hit evaluate.

HTH,
Kent

Kent Boogaart
When I look at the details (which I've done before) the stack trace stops at 'InitializeComponent();' in the main window code behind. If I step into InitializeComponent the exception window pops up at different places and the details are the same as before.
Dan dot net
Usually if the debugger is dying in InitializeComponent is some invalid xaml
Nigel Sampson
yup, it has to be in your xaml. InitializeComponent tries to instantiate all the controls specified in xaml. This may be medieval, but try removing controls in your .xaml until the exception doesn't pop up.
Jose
I created a new usercontrol with only a single dependancyobject that was a string and it worked. I then changed the dependancy object type to int[] and it failed the same way as before. I'm specifying in the frameworkpropertymetadata that the default value is null and I think that is what is screwing me up. I tried 'new int[256]' but that failed too. Any suggestions on a default value or if you think I'm barking up the wrong tree.
Dan dot net
A: 

You could try initialising the array when you initialise FrameworkPropertyMetaData on the dependency property.

 new FrameworkPropertyMetadata(new int [256],
                              FrameworkPropertyMetadataOptions.AffectsRender,  
                              new PropertyChangedCallback(ViewProperty_Changed))

I think that the program might be hitting a null reference exception before it manages to bind the dependency property to the viewmodel property.


Ok I've had a look at your example project and think i have a solution.

change the int[] in the viewmodel to a List<int>. I'm not sure why this works. I hope there is no technical reason that list<int> is not suitable for you.

Here is what I have changed in the solution

in the viewmodel

public List<int> CustomData
        {
            get
            {
                return new List<int>(){0,1,2,3};
            }
            set
            {
            }
        }

In the arraycontrol codebehind

public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data",
                                        typeof(List<int>),
                                        typeof(ArrayControl),
                                        new FrameworkPropertyMetadata(new List<int>()));

        public List<int> Data
        {
            get { return (List<int>)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

In arraycontrol.xaml. Just added listbox to show data binding working

<UserControl x:Class="UserControlWithArray.Controls.ArrayControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
             <TextBlock x:Name="MessageTextBlock" Text="ArrayControl"/> 
        <ListBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=Data}"/>
    </Grid>
</UserControl>
Dave Turvey
I tried that (see my last comment above) but it didn't work :(
Dan dot net
Sorry, I'm not sure which comment you mean. Have you tried replacing the null in your last code snippet with new int[256]?
Dave Turvey
I'f you want to send over the entire project i'll have a look. Although i'm pretty new to wpf so i'm might not get it working either.
Dave Turvey
I recreated the problem in a very small project that can be obtained here: http://www.mediafire.com/?tjntymmi5dz . It's in rar format, let me know if that is going to be a problem and I can zip it. Thanks
Dan dot net
I knew using list worked (like string) but I really want to use an array so that I can insert values by index. I guess string and list work because they can be null?? Thanks for taking the time to look at it!!
Dan dot net
Why don't you use the ToList() and ToArray() methods to convert between them as necessary?
Dave Turvey
I could do the conversion but I thought that if I wanted an array I should be able to do what I want in an array. The solution that I'm going with that I just verified works is to put the array in a class and pass the class around. The class can be null and thus doesn't throw the exception. I'm going to mark your answer as the accepted answer. Thanks again for your help
Dan dot net