1

Whenever I paste the UserControl.DataContext portion of the code below, I get "Object reference not set" in the designer. I'm pretty convinced it's something inside the view model, but I think it has to do with binding because it runs fine...

When the view model loads it makes a call to a WCF service method to fetch a short list of object types for something in the database that then allocates a local list that is bound to in the designer.

Is there anyway to nail down what exactly isn't set? I've tried opening another copy of VS and attaching to process on devenv and xdesproc, but when I do, nothing every shows up in the second VS instance. I'm at a loss for how to narrow this down.

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:f="clr-namespace:FocusVMLib;assembly=FocusVMLib"
xmlns:ViewModels="clr-namespace:SalvageTracking.ViewModels"
mc:Ignorable="d"
x:Class="SalvageTracking.Controls.CompanyEditor"
x:Name="UserControl"
d:DesignWidth="514" d:DesignHeight="280.667">

<UserControl.DataContext>
    <ViewModels:CompanyEditorViewModel x:Name="companyEditorViewModel"/>
</UserControl.DataContext>

<Grid x:Name="LayoutRoot" Background="White" Margin="8,8,8,8" FocusManager.FocusedElement="{Binding ElementName=CompanyNameTextBox}">

    <TextBlock VerticalAlignment="Top" Text="Company Name" TextWrapping="Wrap" HorizontalAlignment="Left"/>
    <TextBox x:Name="CompanyNameTextBox" Text="{f:FocusBinding Path=Name, ValidatesOnDataErrors=True}"
             HorizontalAlignment="Left" Height="23" Margin="0,20.96,0,0" TextWrapping="Wrap"
             VerticalAlignment="Top" Width="120"/>

    <TextBlock VerticalAlignment="Top" Text="Company Type" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="125,0,0,0"/>
    <ComboBox SelectedIndex="{f:FocusBinding Path=TypeIndex, ValidatesOnDataErrors=True}"
              ItemsSource="{Binding CompanyTypes}" DisplayMemberPath="Name"
              HorizontalAlignment="Left" Margin="125,20.96,0,0" VerticalAlignment="Top" Width="121.5"/>

    <TextBlock VerticalAlignment="Top" Text="Company City" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="251.5,0,0,0"/>
    <TextBox  Text="{f:FocusBinding Path=City, ValidatesOnDataErrors=True}"
              HorizontalAlignment="Left" Height="23" Margin="251.5,20.96,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>

    <TextBlock VerticalAlignment="Top" Text="Company State" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="376.5,0,0,0"/>
    <ComboBox Text="{f:FocusBinding Path=State, ValidatesOnDataErrors=True}"
              ItemsSource="{Binding States}" DisplayMemberPath="Name"
              HorizontalAlignment="Left" Margin="376.5,20.96,0,0" VerticalAlignment="Top" Width="121.5"/>

    <TextBlock VerticalAlignment="Top" Text="Company Address 1" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="0,48.96,0,0"/>
    <TextBox  Text="{f:FocusBinding Path=Address1, ValidatesOnDataErrors=True}"
              HorizontalAlignment="Left" Height="23" Margin="0,69.92,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="373"/>

    <TextBlock VerticalAlignment="Top" Text="Company Zip Code" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="378,48.96,0,0"/>
    <TextBox  Text="{f:FocusBinding Path=Zip, ValidatesOnDataErrors=True}"
              HorizontalAlignment="Left" Height="23" Margin="378,69.92,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>

    <TextBlock VerticalAlignment="Top" Text="Company Address 2" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="0,97.92,0,0"/>
    <TextBox Text="{f:FocusBinding Path=Address2, ValidatesOnDataErrors=True}"
             HorizontalAlignment="Left" Height="23" Margin="0,118.88,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="498"/>

    <TextBlock VerticalAlignment="Top" Text="Company Phone #" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="0,146.88,0,0"/>
    <TextBox Text="{f:FocusBinding Path=Phone, ValidatesOnDataErrors=True}" HorizontalAlignment="Left" Height="23"
             Margin="0.001,167.84,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>

    <TextBlock VerticalAlignment="Top" Text="Company Fax #" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="125.001,146.88,0,0"/>
    <TextBox Text="{f:FocusBinding Path=Fax, ValidatesOnDataErrors=True}" HorizontalAlignment="Left" Height="23"
             Margin="125.001,167.84,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>

    <TextBlock VerticalAlignment="Top" Text="Company Email" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="250.001,146.88,0,0"/>
    <TextBox Text="{f:FocusBinding Path=Email, ValidatesOnDataErrors=True}"
             HorizontalAlignment="Left" Height="23" Margin="250.001,167.84,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="247.999"/>

    <TextBlock VerticalAlignment="Top" Text="Company URL" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="0,195.84,0,0"/>
    <TextBox Text="{f:FocusBinding Path=Url, ValidatesOnDataErrors=True}"
             HorizontalAlignment="Left" Height="23" Margin="0,216.801,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="498"/>

    <CheckBox IsChecked="{Binding CanPostOnline, Mode=TwoWay}" Content="Can Post Online"
              HorizontalAlignment="Left" Margin="0,247.801,0,0" VerticalAlignment="Top"/>

    <Button Content="Save" Style="{StaticResource GreenButtonStyle}" Command="{Binding SaveCommand}"
            CommandParameter="{Binding ElementName=UserControl}" IsDefault="True"
            HorizontalAlignment="Left" Margin="343,244.801,0,0" VerticalAlignment="Top" Width="75"/>
    <Button Content="Cancel" Style="{StaticResource GrayButtonStyle}" Command="{Binding CancelCommand}"
            CommandParameter="{Binding ElementName=UserControl}" IsCancel="True"
        HorizontalAlignment="Left" Margin="423,244.801,0,0" VerticalAlignment="Top" Width="75"/>

</Grid> 

Edit: I commented out the DataContext setting in the xaml and did this in the code behind to set up the data context and it got rid of the object not set if that gives any clues.

public partial class CompanyEditor : UserControl
{
    public ViewModels.CompanyEditorViewModel companyEditorViewModel = null;
    public CompanyEditor() 
    {
        this.InitializeComponent();

        companyEditorViewModel = new ViewModels.CompanyEditorViewModel();
        this.DataContext = companyEditorViewModel;
    }
}
steviesama
  • 337
  • 4
  • 13
  • 1
    I often have this problem too, and I think it's just an issue with the parsing engine that detects that there is somewhere an unintialized object in the Viewmodel. However it will just run fine if it's actually initialized before use, and the parsing engine just doesn't check that. – Lennart Jun 17 '15 at 08:10
  • So this just happens when you do some dynamic loading during construction on a data bound field I guess? – steviesama Jun 17 '15 at 08:13
  • Do you find the code behind data context setup not-horrible as a means of getting rid of the error? I just can't stand it. It makes blend crash if I happen to be making ui changes. – steviesama Jun 17 '15 at 08:14
  • I rarely use the DataContext assignment via XAML since you can't pass any parameters to the ctor which makes Dependency Injection difficult. If you initialize affected fields with dummy data (that gets almost immediately overwritten in the ctor), the warning should go away. And assigning the DataContext in code behind is fine. If you need a design-time data context, you can always use d:DataContext. – Lennart Jun 17 '15 at 08:16
  • 2
    The key idea here is that properties set in XAML are probably gonna try to be initialized by the designer. If your ViewModel can't be instantiated right away without extra dependencies, it's probably gonna fail and throw some exception, causing the designer to crash. You could create a dumb constructor for your VM, or set the design-time DataContext as Lennart said... Or do it in code-behind, which is perfectly fine. – almulo Jun 17 '15 at 08:30
  • Also, if you wanna know exactly what's making it crash, you can debug the designer by attaching another Visual Studio instance to it, and then reloading the designer. – almulo Jun 17 '15 at 08:31
  • @almulo I tried attaching to process, it didn't have any results. – steviesama Jun 17 '15 at 14:00

1 Answers1

3

When you set the DataContext in XAML, the designer instantiates the object. Therefore the code in the object's constructor will be executed.

If your constructor does anything fancy which may need to reference another class, or create objects, you will likely get errors, but only in design-time.

There are a few ways you can get around this.

  1. Check your constructors. Ensure that there cannot be a scenario where you will be referencing objects that are null. if (theClassIWant != null) ... for example.
  2. Make use of design-time DataContext. See here
  3. It is possible to work out whether the view is currently in design time. Caliburn Micro has this built in, you can see an example here. That being said, you do not have to use Caliburn Micro, there are other ways.
  4. Setting the DataContext in code-behind is possible. However you will still have the same problem if you add your UserControl to a Window as the UserControl will be instantiated, and by extension, it's DataContext.
  5. My personal favourite, turn off design-time.
Mike Eason
  • 9,525
  • 2
  • 38
  • 63
  • Actually when I add the DataContext in code-behind the object reference not set went away. I added that as an edit. I'll check out the other information though. – steviesama Jun 17 '15 at 13:59
  • Point 5 is my favourite, too :P @steviesama, what he's refering to is that if you use your UserControl in another View or UserControl, you'll get this same error there because the designer will try to instantiate your UserControl, and will run its constructor (and hence try to instantiate the viewmodel, that will fail again). – almulo Jun 17 '15 at 14:05
  • @almulo I understood what he meant. But I was saying that when I set the data context in the code-behind, it didn't actually still give me the error. I just don't want to set the data context in the code-behind on one control and in xaml in every other. I generally prefer just using the xaml view, but sometimes I do some layout in blend for sweeping setups, and then I go back into VS and reorganize it in xaml for tab order, etc. – steviesama Jun 17 '15 at 21:30
  • I went ahead and picked this as the answer. I THINK I've resolved it. There was something 2-3 layers below the view model that may have caused it. I can't be sure because there doesn't appear to be a debug route because it's some wonky crap the designer is doing with the IDataErrorInfo implementation I provided to some underlying data models. There seems to be a case where the design is routing bound field names through the underlying data model. It tried to access this[propertyName] with a property name that wasn't apart of the underlying model. – steviesama Jun 18 '15 at 04:34