Archive

Archive for the ‘RadChartView’ Category

[Telerik] : SelectedItem dans les BarSeries du RadChartView

7 décembre 2012 2 commentaires

Je partage une petite astuce permettant de disposer de la sélection sur le composant RangeBar du RadCartesianChart de Telerik.
Nativement le composant n’offre pas un moyen simple de connaitre l’élément actuellement sélectionné via le pattern MVVM.
Pour cela j’ai dérivé le composant RadSerie afin de lui apporter cette fonctionnalité, dont voici le code :


/// <summary>
    /// Extended <see cref="BarSeries"/> that support a selected item
    /// </summary>
    public class ExtendedBarSeries : BarSeries
    {
        #region Members

        private ChartSelectionBehavior _selectionBehavior;

        #endregion

        #region DPs

        /// <summary>
        /// Define the selected item dependency property
        /// </summary>
        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(Object), typeof(ExtendedBarSeries), new PropertyMetadata(null, SelectedItemChanged));

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the current selected item
        /// </summary>
        public Object SelectedItem
        {
            get
            {
                return GetValue(SelectedItemProperty);
            }
            set
            {
                SetValue(SelectedItemProperty, value);
            }
        }

        #endregion

        #region Handlers

        /// <summary>
        /// Occurs when the presenter has been successfully attached to its owning Telerik.Windows.Controls.ChartView.RadChartBase instance.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            _selectionBehavior = Chart.Behaviors.OfType<ChartSelectionBehavior>().FirstOrDefault();

            if (_selectionBehavior == null)
            {
                _selectionBehavior = new ChartSelectionBehavior();
                Chart.Behaviors.Add(_selectionBehavior);
            }

            _selectionBehavior.SelectionChanged += OnSelectionBehaviorSelectionChanged;
        }

        /// <summary>
        /// Occurs when the presenter has been successfully detached from its owning Telerik.Windows.Controls.ChartView.RadChartBase instance.
        /// </summary>
        /// <param name="oldChart">The old chart instance</param>
        protected override void OnDetached(RadChartBase oldChart)
        {
            base.OnDetached(oldChart);

            if (_selectionBehavior != null)
            {
                _selectionBehavior.SelectionChanged -= OnSelectionBehaviorSelectionChanged;
                oldChart.Behaviors.Add(_selectionBehavior);
                _selectionBehavior = null;
            }
        }

        /// <summary>
        /// Occurs when the chart selection has changed.
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">The chart selection arguments</param>
        private void OnSelectionBehaviorSelectionChanged(object sender, ChartSelectionChangedEventArgs e)
        {
            DataPoint dp = Chart.SelectedPoints.FirstOrDefault(p => p.IsSelected);

            SetValue(SelectedItemProperty, (dp != null) ? dp.DataItem : null);
        }

        /// <summary>
        /// Occurs when the selected item dependency property value changed
        /// </summary>
        /// <param name="d">The dependecy object</param>
        /// <param name="e">The dependency value changes</param>
        private static void SelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var serie = d as ExtendedBarSeries;

            if (serie != null)
            {
                List<CategoricalDataPoint> serieItems = serie.DataPoints.OfType<CategoricalDataPoint>().ToList();

                if (serie._selectionBehavior != null)
                {
                    if (e.NewValue == null)
                    {
                        serie._selectionBehavior.ClearSelection(true, false);
                    }
                    else
                    {
                        CategoricalDataPoint p = serieItems.FirstOrDefault(dp => dp.DataItem == e.NewValue);

                        if (p != null)
                        {
                            if (!serie.Chart.SelectedPoints.Contains(p))
                            {
                                serie._selectionBehavior.ClearSelection(true, false);
                                p.IsSelected = true;
                            }
                        }
                    }
                }
            }
        }

        #endregion
    }

Maintenant a des fins de tests nous faisons rapidement deux classes pour simuler les données:

    public class Data
    {
        public String X
        {
            get;
            set;
        }
        public Int32 Y
        {
            get;
            set;
        }
    }

Puis un manager de données :

 public class DataManager : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private Data _selectedItem;
        private readonly List<Data> _items;

        public DataManager()
        {
            Random r = new Random();
            _items = new List<Data>();

            for (int i = 0; i < 20; i++)
            {
                _items.Add(new Data()
                {
                    X = i.ToString(),
                    Y = r.Next(0, 30)
                });
            }
        }

        public List<Data> Items
        {
            get
            {
                return _items;
            }
        }

        public Data SelectedItem
        {
            get
            {
                return _selectedItem;
            }
            set
            {
                if (_selectedItem == value)
                    return;

                _selectedItem = value;
                OnPropertyChanged("SelectedItem");
            }
        }

        public void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Enfin nous créons une instance de la classe DataManager que nous affectons au DataContext de notre vue

/// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new DataManager();
        }
    }

Pour terminer nous créons une vue avec le graphique Telerik, notre composant ExtendedBarSeries et une ComoboBox nous permettant d’effectuer une sélection « programmé » par autre chose qu’un click sur le graphe.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
        xmlns:controls="clr-namespace:TelerikChartViewSelection"
        x:Class="TelerikChartViewSelection.MainWindow"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <!--COMBO-->
        <ComboBox ItemsSource="{Binding Items}"
                  SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                  DisplayMemberPath="X" />

        <!--CHART-->
        <telerik:RadCartesianChart Grid.Row="1">

            <telerik:RadCartesianChart.HorizontalAxis>
                <telerik:CategoricalAxis />
            </telerik:RadCartesianChart.HorizontalAxis>

            <telerik:RadCartesianChart.VerticalAxis>
                <telerik:LinearAxis />
            </telerik:RadCartesianChart.VerticalAxis>

            <telerik:RadCartesianChart.Grid>
                <telerik:CartesianChartGrid MajorLinesVisibility="Y" />
            </telerik:RadCartesianChart.Grid>

            <telerik:RadCartesianChart.SelectionPalette>
                <telerik:ChartPalette>
                    <telerik:ChartPalette.GlobalEntries>
                        <telerik:PaletteEntry Fill="Orange" />
                    </telerik:ChartPalette.GlobalEntries>
                </telerik:ChartPalette>
            </telerik:RadCartesianChart.SelectionPalette>

            <controls:ExtendedBarSeries ItemsSource="{Binding Items}"
                                        SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                                        ValueBinding="Y"
                                        CategoryBinding="X" />
        </telerik:RadCartesianChart>

    </Grid>
</Window>

Enfin voici le résultat final :

Telerik-BarSerie-RadChartView-Selection-MVVM

Vous pouvez désormais manipuler en MVVM le composant BarSeries 🙂

Code source de l’exemple (à renommer) : TelerikChartViewSelection.7z

Publicités
Catégories :RadChartView, Silverlight, Telerik, WPF