在设置datacontext时,如何摆脱设计时XAML错误“对象引用未设置为对象实例”

时间:2015-10-01 13:23:13

标签: xaml mvvm viewmodel datacontext design-time

我又回来了。

当我添加viewmodel的设计时datacontext时,我的XAML设计器中出现“对象引用未设置为对象实例”的错误。

enter image description here

我尝试使用visual studio进行调试,希望得到一些答案,但没有任何显示。一切正常,但如果实际上有错误,我不能依赖这个事实。

<Window x:Class="ISynergy.Views.Relations.Editors.ServicingProduct"
    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:local="clr-namespace:ISynergy.Views.Relations.Editors"
    xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
    xmlns:Controls="clr-namespace:ISynergy.Controls;assembly=I-Synergy.Controls"
    xmlns:Converters="clr-namespace:ISynergy.Controls.Converters;assembly=I-Synergy.Controls" 
    mc:Ignorable="d"
    Title="ServicingProduct" Width="700" WindowStartupLocation="CenterScreen"
    xmlns:ViewModels="clr-namespace:ISynergy.Models.Relations.Editors;assembly=I-Synergy.Models" 
    d:DataContext="{d:DesignInstance {x:Type ViewModels:ServicingProduct_ViewModel}, IsDesignTimeCreatable=True}"
    Style="{DynamicResource StandardDialogWindow}">

<Grid Grid.Row="1" syncfusion:SkinStorage.VisualStyle="Metro" syncfusion:SkinStorage.MetroBrush="{DynamicResource Foreground}">
    <Grid.RowDefinitions>
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="28" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="125" />
        <ColumnDefinition />
        <ColumnDefinition Width="30" />
        <ColumnDefinition Width="10" />
        <ColumnDefinition Width="125" />
        <ColumnDefinition />
        <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock Text="Productcode:"  VerticalAlignment="Center"/>
    <TextBlock Text="Artikel:" Grid.Row="4" VerticalAlignment="Center" />
    <TextBlock Text="Uitvoering:" Grid.Row="5" VerticalAlignment="Center" />
    <TextBlock Text="Merk/Fabrikaat:" Grid.Row="8" VerticalAlignment="Center" />
    <TextBlock Text="Type:" Grid.Row="9" VerticalAlignment="Center" />
    <TextBlock Text="Serie:" Grid.Row="10" VerticalAlignment="Center" />
    <TextBlock Text="Diepte (mm):" Grid.Row="14" VerticalAlignment="Center" />
    <TextBlock Text="Breedte (mm):" Grid.Row="15" VerticalAlignment="Center" />
    <TextBlock Text="Hoogte (mm):" Grid.Row="16" VerticalAlignment="Center" />
    <TextBlock Text="Gewicht (kg):" Grid.Row="17" VerticalAlignment="Center" />
    <TextBlock Text="Serienummer:" Grid.Row="9" Grid.Column="4" VerticalAlignment="Center" />
    <TextBlock Text="Extra Informatie:" Grid.Row="11" VerticalAlignment="Center" />
    <TextBlock Text="Afbeelding:" Grid.Column="4" VerticalAlignment="Center" />
    <TextBlock Text="Memo:" Grid.Row="18" VerticalAlignment="Center" />
    <TextBlock Text="Ingevoerd door:" Grid.Column="4" Grid.Row="19" Margin="1" VerticalAlignment="Center" />
    <TextBlock Text="Laatst gewijzigd door:" Grid.Column="4" Grid.Row="20" Margin="1" VerticalAlignment="Center" />
    <TextBox Grid.Column="1" AcceptsTab="True" Grid.Row="18" Margin="1" Grid.RowSpan="3" Name="txtMemo" TextWrapping="WrapWithOverflow" TabIndex="26" AcceptsReturn="True" VerticalContentAlignment="Top" />
    <TextBox Grid.Column="1" AcceptsTab="True"  Grid.Row="11" Margin="1" Grid.RowSpan="3" Name="txtExtraInfo" TextWrapping="WrapWithOverflow" TabIndex="19" AcceptsReturn="True" VerticalContentAlignment="Top" />
    <Border Grid.Column="5" Margin="1" Grid.RowSpan="9" BorderThickness="1" BorderBrush="{DynamicResource BorderBrushNormal}">
        <Image Name="pbFoto" />
    </Border>
    <TextBox Grid.Column="5" AcceptsTab="False" Grid.Row="9" Margin="1" Name="txtSerial" TabIndex="18" />

    <syncfusion:IntegerTextBox Height="26" Grid.Column="1" Grid.Row="14" Margin="1" Name="txtL" />
    <syncfusion:IntegerTextBox Height="26" Grid.Column="1" Grid.Row="15" Margin="1" Name="txtB" />
    <syncfusion:IntegerTextBox Height="26" Grid.Column="1" Grid.Row="16" Margin="1" Name="txtH" />
    <syncfusion:DoubleTextBox Height="26" NumberDecimalDigits="2" Grid.Column="1" Grid.Row="17" Margin="1" Name="txtW" />
    <TextBox Grid.Column="1" AcceptsTab="False" Grid.Row="10" Margin="1" Name="txtSerie" TabIndex="6" MaxLength="48" />
    <TextBox Grid.Column="1" AcceptsTab="False" Grid.Row="9" Margin="1" Name="txtModel" TabIndex="5" MaxLength="50" />
    <TextBox Grid.Column="1" AcceptsTab="False" Grid.Row="8" Margin="1" Name="txtMerk" TabIndex="4" MaxLength="50" />
    <TextBox Grid.Column="1" AcceptsTab="True" Grid.Row="5" Margin="1" Grid.RowSpan="3" Name="txtDescLong" TextWrapping="WrapWithOverflow" TabIndex="3" AcceptsReturn="True" VerticalContentAlignment="Top" />
    <TextBox Grid.Column="1" AcceptsTab="False" Grid.Row="4" Margin="1" Name="txtDescShort" TabIndex="2" MaxLength="48" />
    <TextBox Grid.Column="1" AcceptsTab="False" Margin="1" Name="txtNummer" CharacterCasing="Upper" TabIndex="1" MaxLength="25" />
    <Border>
        <Image Grid.Column="5" Grid.RowSpan="9" Stretch="Uniform" Margin="1" Name="pbImage" Height="Auto" MaxHeight="220" VerticalAlignment="Center" />
    </Border>
    <Controls:ToolButton Grid.Column="6" Height="26" Width="26" Source="ISynergy.Resources.Assets.Images.tb_search.xaml" Cursor="Hand" Name="cmdBrowse" />
    <Controls:ToolButton Grid.Column="2" Grid.Row="11" Name="cmdMergeFields" Source="ISynergy.Resources.Assets.Images.tb_search.xaml" Width="26" Height="26" />
    <TextBlock Text="" Grid.Column="5" Grid.Row="19" Name="txtInputFirst" Margin="1" VerticalAlignment="Center" />
    <TextBlock Text="" Grid.Column="5" Grid.Row="20" Name="txtInputLast" Margin="1" VerticalAlignment="Center" />
    <TextBlock Text="Oppervlakte" Grid.Column="4" Grid.Row="14"  Name="lblOppervlakte" VerticalAlignment="Center" />
    <TextBlock Text="Volume" Grid.Column="4" Grid.Row="15" Name="lblVolume" VerticalAlignment="Center" />
    <TextBlock Text="Dichtheid" Grid.Column="4" Grid.Row="16" Name="lblDichtheid" VerticalAlignment="Center" />
    <Controls:ToolButton Name="cmdEditorUitvoering" Grid.Column="2" Grid.Row="5" Source="ISynergy.Resources.Assets.Images.tb_search.xaml" Width="26" Height="26" />
    <Controls:ToolButton Name="cmdEditorNotitie" Grid.Column="2" Grid.Row="18" Source="ISynergy.Resources.Assets.Images.tb_search.xaml" Width="26" Height="26" />
    <TextBlock Text="Adres:" Grid.Row="1" VerticalAlignment="Center" />
    <TextBlock Text="Locatie:" Grid.Row="2" VerticalAlignment="Center" />
    <CheckBox Content="Eigen artikel" Grid.Row="3" VerticalAlignment="Center" Name="chkIsArtikel" />
    <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="4" Margin="0,0,5,0">
        <TextBox Margin="1" Name="txtArtikel" CharacterCasing="Upper" Width="100" />
        <Controls:ToolButton Height="26" Width="26" Source="ISynergy.Resources.Assets.Images.tb_search.xaml" Cursor="Hand" Name="cmdListArtikel" />
        <TextBlock Text="" Name="txtArtikelOmschrijving" />
    </StackPanel>
    <syncfusion:ComboBoxAdv Grid.Column="1" Grid.Row="1" Margin="1" Name="selAdres" />
    <syncfusion:ComboBoxAdv Grid.Column="1" Grid.Row="2" Margin="1" Name="selLocatie" />
    <TextBlock Text="Staat" Grid.Column="4" Grid.Row="10" VerticalAlignment="Center" />
    <syncfusion:ComboBoxAdv Grid.Column="5" Grid.Row="10" Margin="1" Name="selStaat" DisplayMemberPath="Text" SelectedValuePath="Value"/>
    <CheckBox Content="Leverdatum" Grid.Column="4" Grid.Row="11" VerticalAlignment="Center" Name="chkLeverDatum" />
    <DatePicker Grid.Column="5" Grid.Row="11" Width="150" HorizontalAlignment="Left" Margin="1" Name="txtLeverDate" />
    <TextBlock Text="Garantie (maanden):" Grid.Column="4" Grid.Row="12" VerticalAlignment="Center" />
    <syncfusion:IntegerTextBox Height="26" Grid.Column="5" Grid.Row="12" Margin="1,1,78,1" Name="txtGarantie" />
</Grid>

这是我所有继承父母的视图模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ISynergy.Entities.Relations;
using Flurl;
using Flurl.Http;
using ISynergy.Common.Types;
using ISynergy.Library;

namespace ISynergy.Models.Relations.Editors
{
public class ServicingProduct_ViewModel : Base.Base_Relation_Dialog_ViewModel<ISynergy.Entities.Relations.Servicing_Product>
{
    #region "Properties"
    public List<ValuedItem> Product_States { get; set; }

    #endregion

    #region "Constructors"
    public ServicingProduct_ViewModel()
        :base()
    {
        Product_States = new List<ValuedItem>();

        Item = new Servicing_Product() { Relation_Id = Relation.Relation_Id };
        IsNew = true;

        using (BusyIndicator = new Busy())
        {
            Initialization = InitializeAsync();
        }
    }

    public ServicingProduct_ViewModel(Servicing_Product e)
        :this()
    {
        Item = e;
        IsNew = false;
    }
    #endregion

    #region "Initializers"
    public async override Task InitializeAsync()
    {
        await Task.Run(() =>
        {
            Product_States.Clear();
            Product_States.Add(new ValuedItem(0, StringTable.Onbekend));
            Product_States.Add(new ValuedItem(1, StringTable.ArtikelStaatNieuw));
            Product_States.Add(new ValuedItem(2, StringTable.ArtikelStaatGebruikt));
        });
    }
    #endregion

    #region "Events"
    public async override Task Submit(Servicing_Product e)
    {
        if (IsNew == true)
        {
            await new Url(Current.ApiUrl)
                .AppendPathSegment("servicing_products")
                .WithBasicAuth(Current.Username, Current.Password)
                .PostJsonAsync(e);
        }
        else
        {
            await new Url(Current.ApiUrl)
                .AppendPathSegment("servicing_products")
                .WithBasicAuth(Current.Username, Current.Password)
                .PutJsonAsync(e);
        }

        await Item_Changed();
        await Close();
    }
    #endregion
}
}

2 个答案:

答案 0 :(得分:3)

DesignInstance创建ViewModel的实际实例。这意味着在类型的ctor中运行的任何代码都将在Visual Studio和设计器中运行。使用DesignInstance无法阻止这种情况,因为它是按照设计行为。

您可以通过多种方式解决此问题。

首先,不要在你的ctor做任何工作。如果那是不可能的......

在您的ctor工作之前,检查您是否处于设计模式。这是通过GetIsInDesignMode方法完成的。

if(System.ComponentModel.DesignerProperties.GetIsInDesignMode(
    new DependencyObject()))
    return; // short circuit in design mode
InitializeComponentForRuntimeLol();

有些人因为某些原因对此过敏,但如果你不打喷嚏,这是一种选择。

如果您正在打喷嚏,最后一个选项是创建与您的VM具有相同外观的类型,但其中没有任何执行代码。这意味着您将在运行时不需要一些随机类型。

无论如何,目前还没有一个完美的解决方案。有人要求能够使用json来定义设计中用于绑定的对象,但我认为2015年没有采取行动:/

答案 1 :(得分:0)

问题的回答是正确的,因为设计师试图在设计时运行您的viewmodel。让我提供一个替代解决方案,不涉及使您的代码IDE感知。

首先,在xaml中分配DataContext。我通常这样做,但你的方法的变化可能也会起作用:

<WindowClass.DataContext>
    <viewmodels:ViewModel />
</WindowClass.DataContext>

接下来在ViewModel中,从使用数据填充属性的方法中隔离应保留在构造函数中的属性初始化。设计人员将能够初始化所有属性,但不会依赖实际数据的可用性来实例化类。它将具有如下布局:

public class ViewModel
{
    public ObervableCollection<string> ListOfThings { get; set; }

    ViewModel()
    {
        ListOfThings = new ObservableCollection<string>();
    }

    public void PopulateData()
    {
        ListOfThings = DataHelperClass.GetData();
    }
}

这允许设计人员实例化您的类,而无需访问仅在运行时可用的数据或数据检索类。

最后,我们调用该方法从后面的page.xaml.cs代码的构造函数中填充数据。这可以确保它在负载下运行,但不能在设计时运行:

public partial class WindowClass : Window
{
    ViewModel vm = (ViewModel)this.DataContext;
    vm.PopulateData();
}

如果您有多个带有自己的DataContext的控件,您可以使用x:Name命名它们,然后通过将“this”替换为名称来获取后面代码中的视图模型。

进一步说明: 如果你在Windows Form中的一个ElementHost中使用WPF UserControl这样做,你会想要调用在外部Form.cs的构造函数中填充数据,以便windows窗体的设计者作品。你可以这样做:

public FormHost()
{
    InitializeComponent();
    ViewModel vm = (ViewModel)((System.Windows.Controls.UserControl)elementHost1.Child).DataContext;
    vm.PopulateData();
}