【问题标题】:WPF UserControl with ObservableCollection DependencyProperty not binding具有 ObservableCollection DependencyProperty 的 WPF UserControl 未绑定
【发布时间】:2014-05-03 20:53:55
【问题描述】:

我有一个线系列图表的用户控件,并为图表上的项目创建了一堆依赖属性;标题、x 轴标签、数据本身等……数据是 KeyValuePair 的可观察集合。当它在主窗口中时,我的图表工作正常。我的主窗口上必须有 5 个系列图表,所以我认为用户控件将是一个很好的解决方案。我将 xaml 复制并粘贴到一个新的用户控件中。我为我想绑定的所有元素添加了绑定;标题、标签、间隔和数据。然后,我在后面的代码中为所有这些绑定创建了属性,并使用 DependencyProperty.Register 来确保它们会被传递。标题和标签工作得很好,尽管我在主窗口的 xaml 中对它们进行了硬编码。可观察的集合根本没有约束力。我尝试了在这个站点上找到的一堆解决方案(即 - 将 ElementName=NameOfUserControl 添加到绑定,在主窗口的绑定上添加 RelativeSource=UserControl)。我似乎无法让这些数据通过。

如果我不在主窗口中添加 RelativeSource 子句,我会收到此错误:

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“LineGraph”(名称=“我”)上找不到“处置”属性。 BindingExpression:Path=Disposition.WidthData; > DataItem='LineGraph'(名称='我');目标元素是'LineGraph'(名称='Me'); target > 属性是 'ActualData'(类型 'ObservableCollection`1')

我之前遇到过这个问题,最终我放弃了,只是将 xaml 直接放入我的主窗口,而不是使用用户控件。我想弄清楚这一点,以便我可以使用更多用户控件,并且我的主窗口中没有 1000 行 xaml。

这是用户控件 xaml:

<UserControl x:Class="Essar.Dispo.UI.UserControls.LineGraph"
         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:toolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" 
         xmlns:datavis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
         mc:Ignorable="d" x:Name="Me"
         >
<UserControl.Resources>
    <Style TargetType="datavis:Title" x:Key="GraphTitleStyle">
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="FontSize" Value="16" />
        <Setter Property="FontWeight" Value="Bold" />
    </Style>

    <Style TargetType="datavis:Title" x:Key="AxisTitleStyle" BasedOn="{StaticResource GraphTitleStyle}">
        <Setter Property="FontSize" Value="12" />
        <Setter Property="FontWeight" Value="Medium" />
    </Style>

    <Style TargetType="datavis:Legend" x:Key="LegendStyle">
        <Setter Property="Width" Value="0" />
    </Style>

    <Style TargetType="toolkit:AxisLabel" x:Key="AxisLabelStyle">
        <Setter Property="Foreground" Value="Black" />
    </Style>
</UserControl.Resources>
<Grid>
    <toolkit:Chart Name="FinishingMillWidthChart" Title="{Binding MainTitle}" Height="350"
                                       TitleStyle="{StaticResource GraphTitleStyle}"
                                       LegendStyle="{StaticResource LegendStyle}">
        <toolkit:Chart.Axes>
            <toolkit:LinearAxis Orientation="X" Title="{Binding XAxisTitle}" Interval="{Binding XAxisInterval}" ShowGridLines="True" 
                                                    AxisLabelStyle="{StaticResource AxisLabelStyle}" TitleStyle="{StaticResource AxisTitleStyle}" />
            <toolkit:LinearAxis Orientation="Y" Title="{Binding YAxisTitle}" ShowGridLines="True" Interval="{Binding YAxisInterval}" 
                                                    AxisLabelStyle="{StaticResource AxisLabelStyle}" TitleStyle="{StaticResource AxisTitleStyle}" />
        </toolkit:Chart.Axes>
        <toolkit:LineSeries Title="tolerance high" DependentValuePath="Value" IndependentValuePath="Key"
                            ItemsSource="{Binding ToleranceHigh, ElementName=Me}" Visibility="{Binding HighLowVisible}">
            <toolkit:LineSeries.DataPointStyle>
                <Style TargetType="{x:Type toolkit:DataPoint}">
                    <Setter Property="Template" Value="{x:Null}" />
                    <Setter Property="Background" Value="YellowGreen" />
                </Style>
            </toolkit:LineSeries.DataPointStyle>
        </toolkit:LineSeries>
        <toolkit:LineSeries Title="actual" DependentValuePath="Value" IndependentValuePath="Key"
                            ItemsSource="{Binding ActualData, ElementName=Me}">
            <toolkit:LineSeries.DataPointStyle>
                <Style TargetType="{x:Type toolkit:DataPoint}">
                    <Setter Property="Template" Value="{x:Null}" />
                    <Setter Property="Background" Value="Maroon" />
                </Style>
            </toolkit:LineSeries.DataPointStyle>
        </toolkit:LineSeries>
        <toolkit:LineSeries Title="tolerance low" DependentValuePath="Value" IndependentValuePath="Key"
                            ItemsSource="{Binding ToleranceLow, ElementName=Me}" Visibility="{Binding HighLowVisible}">
            <toolkit:LineSeries.DataPointStyle>
                <Style TargetType="{x:Type toolkit:DataPoint}">
                    <Setter Property="Template" Value="{x:Null}" />
                    <Setter Property="Background" Value="DarkCyan" />
                </Style>
            </toolkit:LineSeries.DataPointStyle>
        </toolkit:LineSeries>
    </toolkit:Chart>
</Grid>

下面是用户控件的代码:

public partial class LineGraph : UserControl
{
    public LineGraph()
    {
        InitializeComponent();
        DataContext = this;
    }

    #region Properties
    public static readonly DependencyProperty MainTitleProperty = DependencyProperty.Register("MainTitle", typeof(string), typeof(LineGraph));
    public string MainTitle
    {
        get { return GetValue(MainTitleProperty).ToString(); }
        set { SetValue(MainTitleProperty, value); }
    }


    public static readonly DependencyProperty XAxisTitleProperty = DependencyProperty.Register("XAxisTitle", typeof(string), typeof(LineGraph));
    public string XAxisTitle
    {
        get { return GetValue(XAxisTitleProperty).ToString(); }
        set { SetValue(XAxisTitleProperty, value); }
    }


    public static readonly DependencyProperty YAxisTitleProperty = DependencyProperty.Register("YAxisTitle", typeof(string), typeof(LineGraph));
    public string YAxisTitle
    {
        get { return GetValue(YAxisTitleProperty).ToString(); }
        set { SetValue(YAxisTitleProperty, value); }
    }


    public static readonly DependencyProperty XAxisIntervalProperty = DependencyProperty.Register("XAxisInterval", typeof(double), typeof(LineGraph));
    public double XAxisInterval
    {
        get { return Common.DoubleParse(GetValue(XAxisIntervalProperty)); }
        set { SetValue(XAxisIntervalProperty, value); }
    }

    public static readonly DependencyProperty YAxisIntervalProperty = DependencyProperty.Register("YAxisInterval", typeof(double), typeof(LineGraph));
    public double YAxisInterval
    {
        get { return Common.DoubleParse(GetValue(YAxisIntervalProperty)); }
        set { SetValue(YAxisIntervalProperty, value); }
    }


    public static readonly DependencyProperty ToleranceHighProperty = DependencyProperty.Register("ToleranceHigh", typeof(ObservableCollection<KeyValuePair<double, double>>), typeof(LineGraph));
    public ObservableCollection<KeyValuePair<double, double>> ToleranceHigh
    {
        get 
        {
            return GetValue(ToleranceHighProperty) as ObservableCollection<KeyValuePair<double, double>>; 
        }
        set { SetValue(ToleranceHighProperty, value); }
    }

    public static readonly DependencyProperty ActualDataProperty = DependencyProperty.Register("ActualData", typeof(ObservableCollection<KeyValuePair<double, double>>), typeof(LineGraph));
    public ObservableCollection<KeyValuePair<double, double>> ActualData
    {
        get
        {
            return GetValue(ActualDataProperty) as ObservableCollection<KeyValuePair<double, double>>;
        }
        set { SetValue(ActualDataProperty, value); }
    }

    public static readonly DependencyProperty ToleranceLowProperty = DependencyProperty.Register("ToleranceLow", typeof(ObservableCollection<KeyValuePair<double, double>>), typeof(LineGraph));
    public ObservableCollection<KeyValuePair<double, double>> ToleranceLow
    {
        get
        {
            return GetValue(ToleranceLowProperty) as ObservableCollection<KeyValuePair<double, double>>;
        }
        set { SetValue(ToleranceLowProperty, value); }
    }

    public Visibility HighLowVisible
    {
        get
        {
            if (ToleranceHigh == null || ToleranceLow == null)
                return Visibility.Hidden;
            return Visibility.Visible;
        }
    }

    #endregion
}

请注意,Common.DoubleParse 是我的框架中的一个函数,它执行 double.TryParse,真的没什么特别的。

最后这是我主窗口中的 xaml,不确定这是否重要,但图表位于 tabitem、scrollviewer 和停靠面板中。

<uc:LineGraph MainTitle="finishing mill width" Margin="5"
              XAxisTitle="length (meters)" XAxisInterval="10" 
              YAxisTitle="millimeters" YAxisInterval="15"
              ToleranceHigh="{Binding Disposition.WidthToleranceHigh}"
              ActualData="{Binding Disposition.WidthData}"
              ToleranceLow="{Binding Disposition.WidthToleranceLow}"/>

另一个注意事项,我的 MainWindowViewModel 有一个名为 Disposition 的属性,它是另一个具有自己属性的视图模型。请记住,当图表位于完全相同的位置但完整写出时,它工作得很好。我在想我在主窗口或用户控件中的绑定缺少一些愚蠢的东西。

任何帮助表示赞赏:-)

【问题讨论】:

    标签: wpf mvvm user-controls observablecollection dependency-properties


    【解决方案1】:

    永远不要将你的用户控件的数据上下文设置为这个!所以只需在你的ctor中删除你的行。

    public LineGraph()
    {
        InitializeComponent();
    }
    

    现在你当然应该在所有绑定中添加你的元素名称,例如。

            <toolkit:LinearAxis Orientation="X" 
                 Title="{Binding XAxisTitle, ElementName=Me}" 
                 Interval="{Binding XAxisInterval, ElementName=Me}" 
                 ShowGridLines="True" AxisLabelStyle="{StaticResource AxisLabelStyle}" TitleStyle="{StaticResource AxisTitleStyle}" />
    

    编辑:您可以试试这段代码,看看您是否绑定到您的收藏作品?

    <UserControl x:Class="Essar.Dispo.UI.UserControls.LineGraph"
         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:toolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" 
         xmlns:datavis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
         mc:Ignorable="d" x:Name="Me"
         >
    <Grid>
    <ItemsControl ItemsSource="{Binding Path=ActualData, ElementName=Me}"/>
    </Grid>
    

    并在您的主视图中添加以下内容

    <uc:LineGraph MainTitle="finishing mill width" Margin="5"
              XAxisTitle="length (meters)" XAxisInterval="10" 
              YAxisTitle="millimeters" YAxisInterval="15"
              ToleranceHigh="{Binding Disposition.WidthToleranceHigh}"
              ActualData="{Binding Disposition.WidthData}"
              ToleranceLow="{Binding Disposition.WidthToleranceLow}"/>
    <ItemsControl ItemsSource="{Binding Disposition.WidthData}"/>
    

    两个项目控件应该显示相同。

    顺便说一句,您可以在运行时使用SNOOP检查您的绑定

    【讨论】:

    • 当我将数据上下文设置为此我的标题和标签时。我注释掉了该行并将 ElementName=Me 添加到我的所有绑定中,因此标题和标签有效,但我的图表仍未填充。这很奇怪,我的输出中的项目出现错误> 找不到与引用'ElementName = Me'进行绑定的源。绑定表达式:路径=XAxisTitle;数据项=空;目标元素是'LinearAxis'(名称='');目标属性是“标题”(类型“对象”)
    • 实际上,我收回了这一点,由于某种原因,图表标题有效,但 x 和 y 轴标签无效。我不得不重新添加 DataContext = this;行并删除 ElementName = Me 以使其工作。我回到第一方;标签都在工作,但我的行数据是空白的。我在我的依赖寄存器行中添加了一个回调函数,并且数据正在正确发送。我想也许我可以使用 INotifyPropertyChange 接口来触发可观察集合的绑定,但所有依赖项都是静态的。我将它添加到属性中,但它不起作用。
    • this.DataContext=this;是不对的,你必须在使用依赖属性时删除它。查看 H.B. 的 cmets。在stackoverflow.com/questions/11226843/…stackoverflow.com/questions/12404337/…
    • 好吧,我同意 DataContext 不应该在构造函数中,但是当我删除它时,我失去了更多的绑定。奇怪的是,唯一绑定的是图表标题。现在我认为 x 和 y 轴上的绑定不起作用,因为它们是 toolkit:chart 的子项。我尝试使用 ElementName=Me, ElementName=LineSeriesChart (图表控件的名称),最后尝试使用一堆不同的相对源行。我真的很讨厌绑定不起作用:-(
    • 绑定真的很简单:) 你所要做的就是像你一样为你的用户控件设置 x:Name 属性,并且没有 this.datacontext =this 或类似的东西。因为您已经在那里定义了您的 DP,现在在您的用户控件的 xaml 中,您使用 ElementName-Binding 绑定到此 DP。就是这样 :) 你用 itemscontrol 尝试了我的 usercontol xaml 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 2011-06-29
    • 2012-06-06
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    相关资源
    最近更新 更多