在WPF设计器中,对象引用未设置为对象的实例,位于x:引用

时间:2016-07-14 14:59:05

标签: c# wpf xaml mvvm dependency-properties

首先,我当然知道这是最重复的问题之一......我会告诉你一点,这有点麻烦。

首先,设置

<UserControl {d:DesignInstance Type=MyControl, IsDesignTimeCreatable=True}>
    <Grid x:Name="root">
        <FrameElement x:Name="ContextProxy" Visibility="Collapsed" />
        ...
        <DataGridTextColumn.Visibility>
            <!-- squiggly line on the SOURCE part -->
            <Binding Source="{x:Reference Name=ContextProxy}"
                     Path=DataContext.IncludeThisColumn
                     />
        </DataGridTextColumn.Visibility>
    </Grid>
</UserControl>

代码隐藏

public partial class MyControl {

    // viewmodel for INPC (data lookups, child controls, etc)
    public ViewModels.vmMyControl { get; } = new ViewModels.vmMyControl();

    MyControl() { // ctor
        this.root.DataContext = this; // to support DependencyProperty
    }

    // several dependency properties for external use/bindings
    public static DP IncludeThisColumnDP = DP.Register(..., OnIncludeThisColumnChanged)
    public bool IncludeThisColumn { GetValue(DP); } { SetValue(DP, value); }

    // relay DP changes from parent / outside world, to internal ViewModel
    private void OnIncludeThisColumnChanged(..)
    { (o as vmMyControl).ViewModel.IncludeThisColumn = e.NewValue; }
}

视图模型

public class vmMyControl {

    private readonly myObservableINPC<bool> _IncludeThisColumn;
    public bool IncludeThisColumn { get/set for _IncludeThisColumn.Value }

    public vmMyControl() { // ctor
        // initialize INPC crap
        this.IncludeThisColumn = new blah(nameof(IncludeThisColumn));

        // data for designer
        if (...GetIsInDesignMode)
            Data_LoadMock();
    }

    public Data_LoadMock() {
        // populate some of the data points
    }
}

所以一般来说,我认为我遵循最佳实践(除了混合DP / INPC,但它很好地解决了我的需求,所以无论如何)...

  • 用户控件的数据上下文应用于内部根元素(顶级网格)

  • 将数据上下文设置为usercontrol的实例以启用DP。

  • 用户控件实例具有初始化为ViewModel的readonly属性

  • viewmodel使用GetIsInDesignMode来确保数据不会加载(实际上,代码的DAL代理也会检查内部bool,以指示它们何时作为单元测试运行,使用InternalsVisibleTo(UnitTestProject)进一步确认他们已被禁用

  • 由于datagrid列可见性不能直接绑定(不在元素树或其他任何内容),我添加了一个FrameworkElement作为datacontext的代理

扭曲

所以,首先让我说在运行时,代码可以工作。所有绑定,数据加载等都没有例外。这纯粹是一个设计时问题,但它让我感到困扰。

由于我在处理w / WPF设计模式时意识到空引用问题,我在看到问题时的第一个操作是添加:

MyControlTests.cs

[TestMethod]
public void InstantiateVM() {
    Action a = () => { return new vmMyControl(); }
    a.ShouldNotThrow(); // FluentAssertions
}

[TestMethod]
public void InstantiateUC() {
    Action a = () => { return new MyControl(); }
    a.ShouldNotThrow(); // FluentAssertions
}

这就是......两个测试都成功运行......并且在检查(调试+断点)时,对象中的任何属性都不会导致异常。

环境

App正在使用框架4.5和C#6(因为我在VS2015上)

我看到有人发布关于VS2015悬停在消息上的帖子以获取更多信息,但它似乎并没有为我做任何事情。

对于它的价值,我使用VS2015 REL ...很想应用更新2或3,但似乎有一些错误来自我所在的地方听力/读取。

1 个答案:

答案 0 :(得分:0)

根据http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

public class BindingProxy : Freezable
{
#region Overrides of Freezable

protected override Freezable CreateInstanceCore()
{
    return new BindingProxy();
}

#endregion

public object Data
{
    get { return (object)GetValue(DataProperty); }
    set { SetValue(DataProperty, value); }
}

// Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

然后

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

<DataGridTemplateColumn.Visibility>
    <Binding Source="{StaticResource ResourceKey=DataContextProxy}"
             Path="Data.IncludeThisColumn"
             Converter="{StaticResource ResourceKey=BoolToHiddenConverter}"
             />
</DataGridTemplateColumn.Visibility>