将 WPF 从 .NET 4 更新到 4.5.2,DataGridTextColumn 可见性 DataContext 引用已损坏

Update WPF from .NET 4 to 4.5.2, DataGridTextColumn Visibility DataContext reference broken

我已将一个 WPF 项目升级到 .NET 4.5.2。在 xaml 文件中,我有以下行。

<UserControl
        x:Class="Casa.Project.Client.Views.Projects.ProjectSearch"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:controls="clr-namespace:Casa.Project.Core.Wpf.Controls;assembly=Casa.Project.Core.Wpf"
        mc:Ignorable="d"
        d:DesignWidth="700"
        x:Name="ProjectSearchWindow"
    >
<UserControl.Resources>
<DataGridTextColumn x:Key="PlanNumberColumn" Header="Project #" Visibility="{Binding DataContext.ShowPlanNumber, Source={x:Reference ProjectSearchWindow}}" Binding="{Binding ProjectNumber}" />

...

ReSharper 会在整个 Visibility 标签下划线,说 "Object reference not set to an instance of an object",这会产生错误。当我加载以 .NET 4 为目标的旧项目时,该错误不存在。

当我实际上 运行 项目时,使用 DataGridTextColumn 的整个 table 不显示任何值(已正确加载)。

从 .NET 4 到 .NET 4.5.2 是否发生了某些导致此行为的更改?我该如何解决?

所以我没有弄清楚为什么升级会破坏它,但我确实找到了让它工作的方法。

Freezable class 能够获取传递给它的 DataContext,即使它不是 visual/logical 树的一部分。我们在此修复中利用了这一点。

步骤

首先,创建一个继承自 Freezable

的 class
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));
}

其次,将 <helpers:BindingProxy x:Key="proxy" Data="{Binding}" /> 放在 DataGridTextColumn 的周围。将本地更改为 BindingProxy class 的名称空间。更改 DataGrid 以匹配您的根 xaml 的标签。如有必要,将 BindingProxy 的名称空间导入 xaml 文件(如 xmlns:helpers="clr-namespace:Casa.Project.Client.Helpers"

<DataGrid.Resources>
    <helpers:BindingProxy x:Key="proxy" Data="{Binding}" />
    <DataGridTextColumn x:Key="PlanNumberColumn" Header="Project #" Visibility="{Binding Data.ShowPlanNumber, Source={StaticResource proxy}}" Binding="{Binding ProjectNumber}" />
</DataGrid.Resources>

最终代码大致状态

<UserControl
        x:Class="Casa.Project.Client.Views.Projects.ProjectSearch"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:helpers="clr-namespace:Casa.Project.Client.Helpers"
        xmlns:controls="clr-namespace:Casa.Project.Core.Wpf.Controls;assembly=Casa.Project.Core.Wpf"
        mc:Ignorable="d"
        d:DesignWidth="700"
        x:Name="ProjectSearchWindow"
    >
<UserControl.Resources>
    <helpers:BindingProxy x:Key="proxy" Data="{Binding}" />
    <DataGridTextColumn x:Key="PlanNumberColumn" Header="Project #" Visibility="{Binding DataContext.ShowPlanNumber, Source={x:Reference ProjectSearchWindow}}" Binding="{Binding ProjectNumber}" />

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