UWP 错误?绑定到某些嵌套的 DependencyProperty 将不起作用
UWP bugs? Binding to some nested DependencyProperty would not working
我正在开发一个派生自UserControl
的图表控件,一切都很好,直到我发现无法通过绑定设置底轴的DependencyProperty
。这是图表控件的代码片段:
public class AxisBase : FrameworkElement
{
public IList<double> ExtraGridLines
{
get { return (IList<double>)GetValue(ExtraGridLinesProperty); }
set { SetValue(ExtraGridLinesProperty, value); }
}
public static readonly DependencyProperty ExtraGridLinesProperty =
DependencyProperty.Register("ExtraGridLines", typeof(IList<double>), typeof(AxisBase), new PropertyMetadata(null, OnExtraGridLineDataPropertyChanged));
private static void OnExtraGridLineDataPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Problem: data bing would not work, and
//this call back method will never get called!
Debug.WriteLine("ExtraGridLines changed...");
}
}
public sealed partial class MyChart : UserControl
{
public MyChart()
{
this.InitializeComponent();
}
public AxisBase BottomAxis
{
get { return (AxisBase)GetValue(BottomAxisProperty); }
set { SetValue(BottomAxisProperty, value); }
}
public static readonly DependencyProperty BottomAxisProperty =
DependencyProperty.Register("BottomAxis", typeof(AxisBase), typeof(MyChart), new PropertyMetadata(null));
}
这里是绑定代码:
<Page x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
x:Name="rootPage">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:MyChart>
<local:MyChart.BottomAxis>
<local:AxisBase ExtraGridLines="{Binding MyExtraGridLines, ElementName=rootPage}" />
</local:MyChart.BottomAxis>
</local:MyChart>
</Grid>
</Page>
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private List<double> _myExtraGridLines;
public List<double> MyExtraGridLines
{
get { return _myExtraGridLines; }
set
{
_myExtraGridLines = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyExtraGridLines"));
}
}
public MainPage()
{
this.InitializeComponent();
this.MyExtraGridLines = new List<double>() { 10, 100, 1000 };
}
public event PropertyChangedEventHandler PropertyChanged;
}
问题是:绑定似乎从未生效,dp ExtraGridLines
的 PropertyChangedCallback 方法从未被调用。但是这些代码在 WPF 中有效。我的代码有什么问题?或者这是一个错误?
任何想法将不胜感激!
编辑1:
这似乎与数据类型无关,即使我将类型从IList<double>
更改为int
、string
或object
,问题都是一样的。但是,如果我将 AxisBase
的类型从 FrameworkElement
更改为 DependencyObject
,则绑定将起作用。但是这个解决方案是不可接受的,因为 DependencyObject
没有 Style
。
编辑2:
最后,我想我找到了 ElementName 绑定不起作用的原因:ElementName 绑定仅适用于同一 NameScope 中的元素。如果您有兴趣了解更多信息,请查看这两个很好的链接:
和
http://www.cnblogs.com/idior/archive/2010/05/28/1746513.html
顺便说一句:一开始我错了:这些代码在 WPF 中也不起作用。绑定会抛出一个运行时错误:
System.Windows.Data 错误:4:找不到与引用 'ElementName=rootPage' 绑定的源。 BindingExpression:Path=显示轴标签;数据项=空;目标元素是 'AxisBase' (Name='');目标 属性 是 'IsLabelVisible'(类型 'Boolean')
btw 2:要使 DataContext 绑定在上面的代码中工作,AxisBase
应该监听 MyChart
的 DataContext 的变化,或者明确地添加到 MyChart 的逻辑树或可视树.那是我的代码的一个错误。但是由于 NameScope 问题,似乎没有正常或优雅的方法来使 ElementName 在这里绑定。
也许我应该将这个问题的标题更改为:为什么 ElementName 绑定到 UserControl 中的元素在 UWP/WPF 中不起作用?
这可能是 UWP 中传统绑定的错误;然而,对于新的 x:Bind
,以下代码应该可以按预期工作。
<local:AxisBase ExtraGridLines="{x:Bind MyExtraGridLines, Mode=OneWay}" />
请注意,这也会为您带来更好的性能。所以你应该首先考虑使用这种绑定方法。
更新
看起来真正的问题与 ElementName
绑定到祖先有关。但是,如果您通过像这样指定 DataContext
来使用普通的 MVVM 方法 -
MyExtraGridLines = new List<double>() { 10, 100, 1000 };
DataContext = this;
并删除 ElementName
与普通绑定的绑定 -
<local:AxisBase ExtraGridLines="{Binding MyExtraGridLines}" />
同时通过添加 -
确保轴元素在可视化树中
<UserControl x:Class="xxx.MyChart">
<Grid>
<ContentPresenter Content="{x:Bind BottomAxis, Mode=OneWay}" />
</Grid>
</UserControl>
这应该也行。
我正在开发一个派生自UserControl
的图表控件,一切都很好,直到我发现无法通过绑定设置底轴的DependencyProperty
。这是图表控件的代码片段:
public class AxisBase : FrameworkElement
{
public IList<double> ExtraGridLines
{
get { return (IList<double>)GetValue(ExtraGridLinesProperty); }
set { SetValue(ExtraGridLinesProperty, value); }
}
public static readonly DependencyProperty ExtraGridLinesProperty =
DependencyProperty.Register("ExtraGridLines", typeof(IList<double>), typeof(AxisBase), new PropertyMetadata(null, OnExtraGridLineDataPropertyChanged));
private static void OnExtraGridLineDataPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Problem: data bing would not work, and
//this call back method will never get called!
Debug.WriteLine("ExtraGridLines changed...");
}
}
public sealed partial class MyChart : UserControl
{
public MyChart()
{
this.InitializeComponent();
}
public AxisBase BottomAxis
{
get { return (AxisBase)GetValue(BottomAxisProperty); }
set { SetValue(BottomAxisProperty, value); }
}
public static readonly DependencyProperty BottomAxisProperty =
DependencyProperty.Register("BottomAxis", typeof(AxisBase), typeof(MyChart), new PropertyMetadata(null));
}
这里是绑定代码:
<Page x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
x:Name="rootPage">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:MyChart>
<local:MyChart.BottomAxis>
<local:AxisBase ExtraGridLines="{Binding MyExtraGridLines, ElementName=rootPage}" />
</local:MyChart.BottomAxis>
</local:MyChart>
</Grid>
</Page>
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private List<double> _myExtraGridLines;
public List<double> MyExtraGridLines
{
get { return _myExtraGridLines; }
set
{
_myExtraGridLines = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyExtraGridLines"));
}
}
public MainPage()
{
this.InitializeComponent();
this.MyExtraGridLines = new List<double>() { 10, 100, 1000 };
}
public event PropertyChangedEventHandler PropertyChanged;
}
问题是:绑定似乎从未生效,dp ExtraGridLines
的 PropertyChangedCallback 方法从未被调用。但是这些代码在 WPF 中有效。我的代码有什么问题?或者这是一个错误?
任何想法将不胜感激!
编辑1:
这似乎与数据类型无关,即使我将类型从IList<double>
更改为int
、string
或object
,问题都是一样的。但是,如果我将 AxisBase
的类型从 FrameworkElement
更改为 DependencyObject
,则绑定将起作用。但是这个解决方案是不可接受的,因为 DependencyObject
没有 Style
。
编辑2: 最后,我想我找到了 ElementName 绑定不起作用的原因:ElementName 绑定仅适用于同一 NameScope 中的元素。如果您有兴趣了解更多信息,请查看这两个很好的链接: 和 http://www.cnblogs.com/idior/archive/2010/05/28/1746513.html
顺便说一句:一开始我错了:这些代码在 WPF 中也不起作用。绑定会抛出一个运行时错误: System.Windows.Data 错误:4:找不到与引用 'ElementName=rootPage' 绑定的源。 BindingExpression:Path=显示轴标签;数据项=空;目标元素是 'AxisBase' (Name='');目标 属性 是 'IsLabelVisible'(类型 'Boolean')
btw 2:要使 DataContext 绑定在上面的代码中工作,AxisBase
应该监听 MyChart
的 DataContext 的变化,或者明确地添加到 MyChart 的逻辑树或可视树.那是我的代码的一个错误。但是由于 NameScope 问题,似乎没有正常或优雅的方法来使 ElementName 在这里绑定。
也许我应该将这个问题的标题更改为:为什么 ElementName 绑定到 UserControl 中的元素在 UWP/WPF 中不起作用?
这可能是 UWP 中传统绑定的错误;然而,对于新的 x:Bind
,以下代码应该可以按预期工作。
<local:AxisBase ExtraGridLines="{x:Bind MyExtraGridLines, Mode=OneWay}" />
请注意,这也会为您带来更好的性能。所以你应该首先考虑使用这种绑定方法。
更新
看起来真正的问题与 ElementName
绑定到祖先有关。但是,如果您通过像这样指定 DataContext
来使用普通的 MVVM 方法 -
MyExtraGridLines = new List<double>() { 10, 100, 1000 };
DataContext = this;
并删除 ElementName
与普通绑定的绑定 -
<local:AxisBase ExtraGridLines="{Binding MyExtraGridLines}" />
同时通过添加 -
确保轴元素在可视化树中<UserControl x:Class="xxx.MyChart">
<Grid>
<ContentPresenter Content="{x:Bind BottomAxis, Mode=OneWay}" />
</Grid>
</UserControl>
这应该也行。