Привязка WPF не применяется к цели после инициализации - PullRequest
1 голос
/ 16 августа 2010

Я пытаюсь добавить привязку серий в набор графических элементов управления Visifire. Для этого я создал свойство зависимости SeriesSource времени DataSeriesCollection. Это связано с интерфейсом, используя:

`<Chart SeriesSource={Binding Series} />`  

Задача
Когда источник изменяется, вызывается обратный вызов проверки. Значение, которое передается этому, является правильным значением, заполненным ObservableCollection<something>. Сразу после вызова значения проверки вызывается обратный вызов CoerceValue, а отправляемое ему значение - ПУСТО ObservableCollection<something>. Баунти достанется любому, кто сможет:

  1. Получите правильный заполненный ObservableCollection<someting>, переданный обратному вызову CoerceValue ИЛИ
  2. Получите правильное значение, передаваемое в обратный вызов OnSeriesSourceChanged ИЛИ
  3. Объясните мне, как я могу сделать любое из вышеперечисленного:)

Вот шаблон данных для представления:

<DataTemplate DataType="{x:Type vm:ReportViewModel}">
    <Grid Name="rootGrid">
    <visifire:Chart Grid.Row="1" SeriesSource="{Binding Series}">
        <visifire:Chart.AxesX>
                <visifire:Axis Title="X axis" />
        </visifire:Chart.AxesX>
        <visifire:Chart.AxesY>
                <visifire:Axis Title="Y axis" />
        </visifire:Chart.AxesY>
    </visifire:Chart>
    </Grid>
</DataTemplate>

Вот целевое свойство зависимости

    //Getter and setter for Dependency Property
    public ObservableCollection<DataSeries> SeriesSource
    {
        get { return (ObservableCollection<DataSeries>)GetValue(SeriesSourceProperty); }
        set { SetValue(SeriesSourceProperty, value);           }
    }

    // Using a DependencyProperty as the backing store for SeriesSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SeriesSourceProperty =
        DependencyProperty.Register("SeriesSource", typeof(ObservableCollection<DataSeries>), typeof(Chart), new UIPropertyMetadata(new ObservableCollection<DataSeries>(), new PropertyChangedCallback(OnSeriesSourceChange), new CoerceValueCallback(CoerceSeries)), new ValidateValueCallback(ValidateSeriesSource));

    //Value validation callback
    private static bool ValidateSeriesSource(object value)
    {
        if (value as ObservableCollection<DataSeries> != null)
            return true;
        return false;
    }

    //Dependency Property Changed callback
    private static void OnSeriesSourceChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Chart c = d as Chart;
        if (c == null)
            return;
        //This line was causing the issue. It was overriding the setter
        c.SeriesSource = (DataSeriesCollection)e.NewValue;
    }

    //Coerce Value callback
    private static object CoerceSeries(DependencyObject d, object value)
    {
        Chart c = d as Chart;
        var collection = value as System.Collections.ObjectModel.ObservableCollection<Visifire.Charts.DataSeries>;
        foreach (var item in c.Series)
        {
            if (!collection.Contains(item))
                c.Series.Remove(item);
        }
        foreach (var item in collection)
        {
            if (!c.Series.Contains(item))
                c.Series.Add(item);
        }
        return collection;
    }

Новая информация
Значение, полученное обратным вызовом CoerceValue, ВСЕГДА является первым значением, для которого было установлено это свойство. Поэтому, если первое значение, которое я передаю, это список с 1 элементом, оно всегда принудительно возвращает значение в список с одним элементом!

Редактировать: обнаружена проблема, в свойствах изменен обратный вызов. Благодарим Мэтта за то, что он помог мне с обратным вызовом CoerceValue

1 Ответ

2 голосов
/ 16 августа 2010

Это может быть не совсем проблема, но у вас есть логика в вашем сеттере. Этот код не будет выполняться, когда свойство назначено через привязку.

Вместо добавления логики в ваш установщик, рассмотрите возможность использования "принудительного" обратного вызова, который вызывается каждый раз, когда значение присваивается вашему свойству. Подробнее об обратных вызовах "принудительного значения" см. Здесь. Они очень похожи на то, что вы сделали для обратного вызова "свойства изменены".

...