控件内的ObservableCollection未受约束

时间:2017-10-05 10:40:30

标签: c# wpf xaml binding

我有一个Series属性SeriesCollection的图表控件,它继承ObservableCollection<Series>Series的{​​{1}}属性Values继承ChartValues。当我将ObservableCollection<double>添加到Series中的SeriesCollectionXaml绑定由于某种原因无法正常工作,Values永远不会被调用。

但是,如果我将OnValuesChanged()移到Series之外,则会调用SeriesCollection

Chart.cs

OnValuesChanged()

SeriesCollection.cs

public class Chart : Control
{
    public static readonly DependencyProperty SeriesProperty =
        DependencyProperty.Register(nameof(Series), typeof(SeriesCollection), typeof(Chart),
            new PropertyMetadata(default(SeriesCollection),
                (s, e) => (s as Chart)?.OnSeriesChanged()));

    private Canvas _canvas;

    public Chart()
    {
        DefaultStyleKey = typeof(Chart);
    }

    public SeriesCollection Series
    {
        get => (SeriesCollection) GetValue(SeriesProperty);
        set => SetValue(SeriesProperty, value);
    }

    public List<ChartGroup> Groups { get; private set; }

    private void SortChartGroups()
    {
        Groups = new List<ChartGroup>();

        var max = Series.Select(s => s.Values?.Count).Max();

        if (max > 0)
        {
            for (var i = 0; i < max; i++)
            {
                var points = Series.SelectMany(s => s.ChartPoints).Where(c => c.Index == i).ToList();
                Groups.Add(new ChartGroup
                {
                    Index = i,
                    Values = points
                });
            }
        }
    }

    public void OnCollectionChanged()
    {
        Update();

    }

    private void OnSeriesChanged()
    {
        Series.CollectionChanged += (s, e) =>
        {
            OnCollectionChanged();
        };

        OnCollectionChanged();
    }

    protected virtual void Update()
    {
        if (Series.Count > 0)
        {
            SortChartGroups();

            if (Groups.Count > 0)
            {
                var count = Series.Count;

                var values = Groups.SelectMany(g => g.Values.Select(p => p.Value)).ToList();

                var min = values.Min();
                var max = values.Max();

                // Draw here
                // Calculate drawing region

                Draw();
            }
        }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _canvas = GetTemplateChild("PART_Canvas") as Canvas;

        Loaded += (s, e) => Draw();
        SizeChanged += (s, e) => Draw();
    }

    private void Draw()
    {
        if (!IsLoaded || Series == null) return;

        //_canvas.Children.Clear();
    }
}

Series.cs

public class SeriesCollection : ObservableCollection<Series>
{
}

ChartValues.cs

public class Series : DependencyObject
{
    public static readonly DependencyProperty ValuesProperty =
        DependencyProperty.Register(nameof(Values), typeof(ChartValues), typeof(Series),
            new PropertyMetadata(default(ChartValues), 
                (s, e) => (s as Series)?.OnValuesChanged()));

    public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
        nameof(Title), typeof(string), typeof(Series), new PropertyMetadata(default(string)));

    public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
        nameof(Color), typeof(Color), typeof(Series), new PropertyMetadata(default(Color)));

    internal Chart Chart { private get; set; }

    public string Title
    {
        get => (string) GetValue(TitleProperty);
        set => SetValue(TitleProperty, value);
    }

    public Color Color
    {
        get => (Color) GetValue(ColorProperty);
        set => SetValue(ColorProperty, value);
    }

    public ChartValues Values
    {
        get => (ChartValues) GetValue(ValuesProperty);
        set => SetValue(ValuesProperty, value);
    }

    internal List<ChartPoint> ChartPoints { get; private set; }

    private void OnCollectionChanged()
    {
        ChartPoints = new List<ChartPoint>();

        for (var i = 0; i < Values.Count; i++)
        {
            ChartPoints.Add(new ChartPoint
            {
                Title = Title,
                Value = Values[i],
                Index = i
            });
        }

        Chart?.OnCollectionChanged();
    }

    private void OnValuesChanged()
    {
        if (Values != null)
        {
            Values.CollectionChanged += (s, e) =>
            {
                OnCollectionChanged();
            };

            OnCollectionChanged();
        }
    }
}

的Xaml

如果我将public class ChartValues : ObservableCollection<double> { } 移到Series之外,SeriesCollection被调用

,那么对values属性的绑定就有效
OnValuesChanged()

但是,当置于<charts:Series Values="{Binding SomeValues}"/> <charts:Series Values="{Binding OtherValues}" /> 内时,对值的绑定不起作用,该类已初始化,但值属性永远不会被绑定设置,而SeriesCollection从未被调用。调用OnValuesChanged() Chart并且OnSeriesChanged()属性中有2个项目,但Series上的绑定永远不会有效。

Values

我绑定到这些值的原因是我在<charts:Chart> <charts:Chart.Series> <charts:SeriesCollection> <charts:Series Values="{Binding SomeValues}"/> <charts:Series Values="{Binding OtherValues}" /> </charts:SeriesCollection> </charts:Chart.Series> </charts:Chart> 课程中有其他属性,我在Series中设置了我并不真正想要的包含在视图模型中,例如标题和颜色

我已查看过这篇文章Initialize Collection of DataTemplates in XAML的答案,但它似乎无法解决我遇到的问题。

修改 我尝试绑定到用户控件的xaml,但无法找到DataContext。它似乎不是视觉树的一部分?

UserControl

修改

Chart.xaml

<charts:Series Values="{Binding Path=DataContext.SomeValues, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>

Generic.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:charts="<omitted>.Charts">

<Style TargetType="{x:Type charts:Chart}">

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type charts:Chart}">
                <Grid>
                    <ItemsControl ItemsSource="{TemplateBinding Series}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

</Style>

<Style TargetType="{x:Type charts:Series}">

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type charts:Series}">
                <Grid>
                    <ListBox ItemsSource="{TemplateBinding Values}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

</Style>

的App.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<ResourceDictionary.MergedDictionaries>

    <ResourceDictionary Source="/<omitted>;component/Themes/Chart.xaml" />

</ResourceDictionary.MergedDictionaries>

0 个答案:

没有答案