将 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}" />
我已将一个 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
的 classpublic 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}" />