【发布时间】:2016-07-14 14:59:04
【问题描述】:
首先,我当然知道这是要问的最重复的问题之一...我会说这有一个转折来节省您的时间。
首先,设置
<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,但它很好地满足了我的需求,所以无论如何)......
用户控件的数据上下文应用到内部根元素(顶级网格)
数据上下文设置为用户控件实例以启用 DP。
用户控件实例已将只读属性初始化为 ViewModel
viewmodel 使用 GetIsInDesignMode 来确保不加载数据(实际上,代码的 DAL 代理还检查内部布尔值以指示它们何时作为单元测试运行,以进一步确认它们已被禁用, 与 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
}
事情是这样的......两个测试都成功运行......并且经过检查(调试 + 断点),对象中的任何属性都不会导致异常。
环境
应用程序使用框架 4.5 和 C#6(因为我在 VS2015 上)
我看到有人发布有关 VS2015 的帖子,将鼠标悬停在消息上以获取更多信息,但它似乎对我没有任何帮助。
对于它的价值,我使用的是 VS2015 REL... 很想应用更新 2 或 3,但从我听到/读到的内容中似乎到处都有一些错误。
【问题讨论】:
-
另外,我已经确认 GetIsInDesignMode 不是问题,方法是添加早期的“return;”在构造函数中(在用户控件中,它紧跟 InitializeComponents 调用)
-
我开始怀疑设计器中是否还有其他东西需要包含在我的单元测试中……初始化中涉及的东西还是什么? (我没有覆盖任何控件的成员)
-
这是一个已知的 VS 错误,已经存在很长时间了。它只是无法正确处理
x:Reference。尽可能使用与ElementName=的绑定来解决此问题。 -
this.root.DataContext = this; // to support DependencyProperty哦,天哪。使用 `{Binding SomeProperty, ElementName=root} 其中控件的 x:Name 是 root。你这样做会伤害自己。设计师是肮脏的错误错误。一直都是。不要花很多时间担心它们。 -
当然,但是您正在通过(可能)犯另一个错误来纠正一个错误。我只需将用于控制列可见性的逻辑滚动到用户控件本身,然后将任何表示可见性状态的内容绑定到 UC 上的 DP,并触发对其的更改。如果在 UC 中运行不佳,甚至可以扩展 Grid 以创建更好地支持此场景的控件。无论如何,按照最佳判断进行,请小心
DataContext = this;陷阱。
标签: c# wpf xaml mvvm dependency-properties