Search code examples
c#xamluwptelerik

XAML convert a list to a list of controls


I am using UI for UWP from telerik to draw a chart. https://github.com/telerik/UI-For-UWP

I am trying to data bind annotations and have them dynamically displayed.

I have bound one annotations like this:

View

<chart:RadCartesianChart x:Name="OhlcChart" PaletteName="DefaultLightSelected" Grid.Row="1">
            <chart:RadCartesianChart.VerticalAxis>
                <chart:LinearAxis/>
            </chart:RadCartesianChart.VerticalAxis>
            <chart:RadCartesianChart.HorizontalAxis>
                <chart:DateTimeCategoricalAxis LabelFormat="{}{0,0:dd/MM}"/>
            </chart:RadCartesianChart.HorizontalAxis>
            <chart:RadCartesianChart.Annotations>
                <chart:CartesianCustomLineAnnotation
                            HorizontalFrom="{x:Bind ViewModel.Annotations[0].Date1}"
                            VerticalFrom="{x:Bind ViewModel.Annotations[0].Value1}"
                            HorizontalTo="{x:Bind ViewModel.Annotations[0].Date2}"
                            VerticalTo="{x:Bind ViewModel.Annotations[0].Value2}"
                            />

                    </chart:RadCartesianChart.Annotations>
            </chart:RadCartesianChart.Annotations>
</chart:RadCartesianChart>

View Model

public class ChartViewModel : ViewModelBase
{
    public class DataItem 
    {
         public DateTime Date1 { get; set; }
         public double Value1 { get; set; }
         public DateTime Date2 { get; set; }
         public double Value2 { get; set; }
    }
    public DataItem [] Annotations { get; }
}

How can I bind an enumerable amount of annotations like this:

public class ChartViewModel : ViewModelBase
{
    public class DataItem 
    {
         public DateTime Date1 { get; set; }
         public double Value1 { get; set; }
         public DateTime Date2 { get; set; }
         public double Value2 { get; set; }
    }
    public DataItem [] Annotations { get; }
}

RadCartesianChart.Annotations does not have an ItemTemplate property like ListView and GridView.

I want to bind my viewmodel such that there is a CartesianCustomLineAnnotation for each item in my view model array.


Solution

  • I was able to solve my problem like this

    public class ViewModel : ViewModelBase
    {
        public Angle[] Angles
        {
            get => _angles;
            set => SetProperty(ref _angles, value);
        }
    
        public class Angle
        {
            public DateTime Date1 { get; set; }
            public double Value1 { get; set; }
            public double Value2 { get; set; }
            public DateTime Date2 { get; set; }
        }
    }
    

    code behind

    public class ChartPage : Page
    {
        private static readonly DependencyProperty AnnotationsProperty =
            DependencyProperty.RegisterAttached(
                "AnnotationsProperty",
                typeof(Angle[]),
                typeof(ChartPage),
                new PropertyMetadata(Array.Empty<Angle>(), OnAnnotationsChanged));
    
        public static void OnAnnotationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var chart = (RadCartesianChart)d;
            var angles = e.NewValue as Angle[];
            chart.Annotations.Clear();
            if (angles == null || angles.Length == 0)
            {
                return;
            }
    
            angles
                .Select(x => new CartesianCustomLineAnnotation
                {
                    HorizontalFrom = x.Date1,
                    HorizontalTo = x.Date2,
                    VerticalFrom = x.Value1,
                    VerticalTo = x.Value2
                })
                .ToList()
                .ForEach(chart.Annotations.Add);
        }
    
        public ChartPage()
        {
    
            InitializeComponent();
            this.OhlcChart.SetBinding(AnnotationsProperty, new Binding
            {
                Path = new PropertyPath(nameof(ChartViewModel.Angles)),
                Mode = BindingMode.OneWay,
            });
        }
    }
    

    I hope this is the correct approach and doesn't memory leak.