【问题标题】:UWP bugs? Binding to some nested DependencyProperty would not workingUWP 错误?绑定到一些嵌套的 DependencyProperty 不起作用
【发布时间】:2017-11-20 14:41:32
【问题描述】:

我正在开发一个从UserControl 派生的图表控件,一切都很好,直到我发现无法通过绑定设置底部轴的DependencyProperty。下面是图表控件的代码sn-p:

  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&lt;double&gt; 更改为intstringobject,问题也是一样的。但是如果我将AxisBase 的类型从FrameworkElement 更改为DependencyObject,那么绑定就会起作用。但是这个解决方案是不可接受的,因为DependencyObject 没有Style

编辑2: 最后,我想我找到了 ElementName 绑定不起作用的原因:ElementName 绑定仅适用于同一 NameScope 中的元素。如果您有兴趣了解更多信息,请查看以下两个不错的链接: https://stackoverflow.com/questions/18389118/how-does-binding-elementname-work-exactlyhttp://www.cnblogs.com/idior/archive/2010/05/28/1746513.html

btw 1:一开始我错了:这些代码在 WPF 中也不起作用。绑定会引发运行时错误: System.Windows.Data 错误:4:找不到与引用“ElementName=rootPage”绑定的源。 BindingExpression:Path=ShowAxisLabel;数据项=空;目标元素是'AxisBase'(名称='');目标属性是“IsLabelVisible”(类型“布尔”)

btw 2:为了使上述代码中的DataContext绑定起作用,AxisBase应该监听MyChart的DataContext的变化,或者显式添加到MyChart的Logical或Visual树中。这是我的代码的一个错误。但是由于 NameScope 的问题,这里似乎没有正常或优雅的方法来进行 ElementName 绑定。

或许我应该将这个问题的标题改为:为什么 ElementName 绑定到 UserControl 中的元素在 UWP/WPF 中不起作用

【问题讨论】:

    标签: c# wpf uwp windows-store-apps


    【解决方案1】:

    这可能是 UWP 中传统绑定的错误;但是,使用新的x:Bind,以下代码应该可以按预期工作。

    &lt;local:AxisBase ExtraGridLines="{x:Bind MyExtraGridLines, Mode=OneWay}" /&gt;

    请注意,这也会为您提供更好的性能。因此,您应该始终考虑首先使用这种绑定方法。

    更新

    看起来真正的问题与 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>
    

    这应该也可以。

    【讨论】:

    • 是的,x:Bind 确实可以完成这项工作。很好的解决方法!谢谢!但我会等着看这个绑定问题是否可以完全解决。我想看看我的图表控件可以与 x:Bind 和 Binding 绑定。
    • 如果您手动将local:AxisBaseDataContext 设置为this,则正常的绑定应该可以工作。
    • 我还发现 ElementName 源引用是问题所在:如果我将源替换为 StaticResouce,则绑定将起作用。您的解决方案也可以,但要使其更像 MVVM,我需要连接到 MyChart 的 DataContextChanged 事件,并将它的 DataContext 分配给轴。在将您的答案标记为接受之前,我会等着看是否有人可以解释为什么 ElementName 参考在这里不起作用。谢谢
    • 由于 Xaml 的 NameScore 机制,从 UserControl 的子元素绑定 ElementName 似乎是不可能的。我将改用 DataContext 绑定。​​
    猜你喜欢
    • 2012-04-15
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 2020-02-01
    • 2014-03-29
    • 2019-01-28
    • 2018-12-07
    • 2016-01-10
    相关资源
    最近更新 更多