Я пытаюсь добавить привязку Series к набору графических элементов управления Visifire. Для этого я создал свойство зависимости SeriesSource времени DataSeriesCollection
. Это связывается во внешнем интерфейсе с помощью:
`<Chart SeriesSource={Binding Series} />`
Задача
При изменении источника вызывается обратный вызов проверки. Значение, которое передается этому, является правильным значением, заполненным ObservableCollection <что-то>
. Сразу после вызова значения проверки вызывается обратный вызов CoerceValue чем-то, и отправляемое ему значение является ПУСТОЙ ObservableCollection <что-то>
. Баунти достанется любому, кто может:
ObservableCollection
, переданное в обратный вызов CoerceValue ИЛИ Вот шаблон данных для представления:
<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
Это может быть не совсем проблема, но у вас есть логика в вашем сеттере. Этот код не будет выполняться, когда свойство назначается через привязку.
Вместо добавления логики к сеттеру рассмотрите возможность использования «принудительного» обратного вызова, который вызывается каждый раз, когда значение присваивается вашему свойству. См. Здесь для получения дополнительных сведений об обратных вызовах "принуждение значения". Они очень похожи на то, что вы сделали для обратного вызова "свойство изменено".