2009-07-06 3 views
1

Je dois pouvoir spécifier une commande à exécuter lorsque l'événement SelectionChanged se déclenche. Je sais déjà comment implémenter l'interface ICommandSource; Ce que je dois savoir, c'est comment je peux simplement ajouter une commande à la série de colonnes pour gérer l'événement SelectionChanged.Comment puis-je implémenter une ColumnSeries commandable dans le contrôle de graphique WPF Toolkit

Lorsque j'hérite de la classe de base ColumnBarBaseSeries < ...> je dois redéfinir GetAxes() et UpdateDatePoint() dont je ne suis pas sûr comment implémenter.

Répondre

2

Vous pouvez utiliser des comportements attachés pour résoudre ce problème.

Créez un SelectionChangedBehaviour qui envoie un événement selectionChanged à l'élément auquel vous associez le comportement, puis vous pouvez lier n'importe quel ICommand à ce comportement.

Pour en savoir plus sur les comportements attachés -

espoir qui aide

+0

Ceci est une solution bien meilleure que celle que j'ai posté ci-dessous. J'aurais aimé le savoir avant de passer 6 heures à copier le code source de ColumnSeries dans une nouvelle classe. – Jacob

+0

Yup comportements attachés sont grands. Une chose que j'ai remarqué avec le développement WPF ... vous devriez être capable de faire tout ce qui est spécifique à l'interface utilisateur de XAML avec les déclencheurs, les DP et les comportements attachés, et la. Si vous vous trouvez en train de pirater avec du code sur le codebehind alors il y a presque certainement un meilleur moyen. Le seul code que je possède est celui des calculs spécifiques à l'interface utilisateur qui doivent être effectués au moment de l'exécution. –

0

Voici un code qui semble fonctionner pour moi de mettre en œuvre votre propre CommandColumnSeri es, j'ai gagné beaucoup de celui-ci de la source pour les ColumnSeries Sealed Classe:

public class CommandColumnSeries : ColumnBarBaseSeries<ColumnDataPoint> 
{ 
    #region "ICommandSource" 

    [Localizability(LocalizationCategory.NeverLocalize), Category("Action"), Bindable(true)] 
    public ICommand Command 
    { 
     get 
     { 
      return (ICommand)base.GetValue(CommandProperty); 
     } 
     set 
     { 
      base.SetValue(CommandProperty, value); 
     } 
    } 

    [Bindable(true), Category("Action"), Localizability(LocalizationCategory.NeverLocalize)] 
    public object CommandParameter 
    { 
     get 
     { 
      return base.GetValue(CommandParameterProperty); 
     } 
     set 
     { 
      base.SetValue(CommandParameterProperty, value); 
     } 
    } 

    [Category("Action"), Bindable(true)] 
    public IInputElement CommandTarget 
    { 
     get 
     { 
      return (IInputElement)base.GetValue(CommandTargetProperty); 
     } 
     set 
     { 
      base.SetValue(CommandTargetProperty, value); 
     } 
    } 

    public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandColumnSeries), new FrameworkPropertyMetadata(null)); 
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandColumnSeries), new FrameworkPropertyMetadata(null)); 
    public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(CommandColumnSeries), new FrameworkPropertyMetadata(null)); 

    #endregion 

    #region public IRangeAxis DependentRangeAxis 

    /// <summary> 
    /// Gets or sets the dependent range axis. 
    /// </summary> 
    public IRangeAxis DependentRangeAxis 
    { 
     get { return GetValue(DependentRangeAxisProperty) as IRangeAxis; } 
     set { SetValue(DependentRangeAxisProperty, value); } 
    } 

    /// <summary> 
    /// Identifies the DependentRangeAxis dependency property. 
    /// </summary> 
    [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes", Justification = "This member is necessary because the base classes need to share this dependency property.")] 
    public static readonly DependencyProperty DependentRangeAxisProperty = 
     DependencyProperty.Register(
      "DependentRangeAxis", 
      typeof(IRangeAxis), 
      typeof(ColumnSeries), 
      new PropertyMetadata(null, OnDependentRangeAxisPropertyChanged)); 

    /// <summary> 
    /// DependentRangeAxisProperty property changed handler. 
    /// </summary> 
    /// <param name="d">ColumnBarBaseSeries that changed its DependentRangeAxis.</param> 
    /// <param name="e">Event arguments.</param> 
    private static void OnDependentRangeAxisPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     CommandColumnSeries source = (CommandColumnSeries)d; 
     IRangeAxis newValue = (IRangeAxis)e.NewValue; 
     source.OnDependentRangeAxisPropertyChanged(newValue); 
    } 

    /// <summary> 
    /// DependentRangeAxisProperty property changed handler. 
    /// </summary> 
    /// <param name="newValue">New value.</param> 
    private void OnDependentRangeAxisPropertyChanged(IRangeAxis newValue) 
    { 
     this.InternalDependentAxis = (IAxis)newValue; 
    } 
    #endregion public IRangeAxis DependentRangeAxis 

    #region public IAxis IndependentAxis 
    /// <summary> 
    /// Gets or sets the independent category axis. 
    /// </summary> 
    public IAxis IndependentAxis 
    { 
     get { return GetValue(IndependentAxisProperty) as IAxis; } 
     set { SetValue(IndependentAxisProperty, value); } 
    } 

    /// <summary> 
    /// Identifies the IndependentAxis dependency property. 
    /// </summary> 
    [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes", Justification = "This member is necessary because the base classes need to share this dependency property.")] 
    public static readonly DependencyProperty IndependentAxisProperty = 
     DependencyProperty.Register(
      "IndependentAxis", 
      typeof(IAxis), 
      typeof(ColumnSeries), 
      new PropertyMetadata(null, OnIndependentAxisPropertyChanged)); 

    /// <summary> 
    /// IndependentAxisProperty property changed handler. 
    /// </summary> 
    /// <param name="d">ColumnBarBaseSeries that changed its IndependentAxis.</param> 
    /// <param name="e">Event arguments.</param> 
    private static void OnIndependentAxisPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     CommandColumnSeries source = (CommandColumnSeries)d; 
     IAxis newValue = (IAxis)e.NewValue; 
     source.OnIndependentAxisPropertyChanged(newValue); 
    } 

    /// <summary> 
    /// IndependentAxisProperty property changed handler. 
    /// </summary> 
    /// <param name="newValue">New value.</param> 
    private void OnIndependentAxisPropertyChanged(IAxis newValue) 
    { 
     this.InternalIndependentAxis = (IAxis)newValue; 
    } 
    #endregion public IAxis IndependentAxis 



    public CommandColumnSeries() 
    { 
     this.SelectionChanged += new SelectionChangedEventHandler(CommandColumnSeries_SelectionChanged); 
    } 

    private void CommandColumnSeries_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) 
    { 
     if (Command != null) 
     { 
      RoutedCommand routedCommand = Command as RoutedCommand; 
      CommandParameter = e.Source; 

      if (routedCommand != null) 
      { 
       routedCommand.Execute(CommandParameter, CommandTarget); 
      } 
      else 
      { 
       Command.Execute(CommandParameter); 
      } 
     } 
    } 

    protected override void GetAxes(DataPoint firstDataPoint) 
    { 
     // Taken from the source of the ColumnSeries sealed class. 
     GetAxes(
      firstDataPoint, 
      (axis) => axis.Orientation == AxisOrientation.X, 
      () => new CategoryAxis { Orientation = AxisOrientation.X }, 
      (axis) => 
      { 
       IRangeAxis rangeAxis = axis as IRangeAxis; 
       return rangeAxis != null && rangeAxis.Origin != null && axis.Orientation == AxisOrientation.Y; 
      }, 
      () => 
      { 
       IRangeAxis rangeAxis = CreateRangeAxisFromData(firstDataPoint.DependentValue); 
       rangeAxis.Orientation = AxisOrientation.Y; 
       if (rangeAxis == null || rangeAxis.Origin == null) 
       { 
        throw new InvalidOperationException("No Suitable Axes found for plotting range axis."); 
       } 
       DisplayAxis axis = rangeAxis as DisplayAxis; 
       if (axis != null) 
       { 
        axis.ShowGridLines = true; 
       } 
       return rangeAxis; 
      }); 

    } 

    protected override void UpdateDataPoint(DataPoint dataPoint) 
    { 
     // This code taken from the ColumnSeries sealed class. 
     if (SeriesHost == null)//|| PlotArea == null) 
     { 
      return; 
     } 

     object category = dataPoint.ActualIndependentValue ?? (IndexOf<DataPoint>(this.ActiveDataPoints, dataPoint) + 1); 
     Range<UnitValue> coordinateRange = GetCategoryRange(category); 
     if (!coordinateRange.HasData) 
     { 
      return; 
     } 
     else if (coordinateRange.Maximum.Unit != Unit.Pixels || coordinateRange.Minimum.Unit != Unit.Pixels) 
     { 
      throw new InvalidOperationException("This Series Does Not Support Radial Axes"); 
     } 

     double minimum = (double)coordinateRange.Minimum.Value; 
     double maximum = (double)coordinateRange.Maximum.Value; 

     double plotAreaHeight = ActualDependentRangeAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Range.Maximum).Value.Value; 
     IEnumerable<CommandColumnSeries> columnSeries = SeriesHost.Series.OfType<CommandColumnSeries>().Where(series => series.ActualIndependentAxis == ActualIndependentAxis); 
     int numberOfSeries = columnSeries.Count(); 
     double coordinateRangeWidth = (maximum - minimum); 
     double segmentWidth = coordinateRangeWidth * 0.8; 
     double columnWidth = segmentWidth/numberOfSeries; 
     int seriesIndex = IndexOf<CommandColumnSeries>(columnSeries, this); 

     double dataPointY = ActualDependentRangeAxis.GetPlotAreaCoordinate(ToDouble(dataPoint.ActualDependentValue)).Value.Value; 
     double zeroPointY = ActualDependentRangeAxis.GetPlotAreaCoordinate(ActualDependentRangeAxis.Origin).Value.Value; 

     double offset = seriesIndex * Math.Round(columnWidth) + coordinateRangeWidth * 0.1; 
     double dataPointX = minimum + offset; 

     if (GetIsDataPointGrouped(category)) 
     { 
      // Multiple DataPoints share this category; offset and overlap them appropriately 
      IGrouping<object, DataPoint> categoryGrouping = GetDataPointGroup(category); 
      int index = GroupIndexOf(categoryGrouping, dataPoint); 
      dataPointX += (index * (columnWidth * 0.2))/(categoryGrouping.Count() - 1); 
      columnWidth *= 0.8; 
      Canvas.SetZIndex(dataPoint, -index); 
     } 

     if (CanGraph(dataPointY) && CanGraph(dataPointX) && CanGraph(zeroPointY)) 
     { 
      double left = Math.Round(dataPointX); 
      double width = Math.Round(columnWidth); 

      double top = Math.Round(plotAreaHeight - Math.Max(dataPointY, zeroPointY) + 0.5); 
      double bottom = Math.Round(plotAreaHeight - Math.Min(dataPointY, zeroPointY) + 0.5); 
      double height = bottom - top + 1; 

      Canvas.SetLeft(dataPoint, left); 
      Canvas.SetTop(dataPoint, top); 
      dataPoint.Width = width; 
      dataPoint.Height = height; 
     } 
    } 

    private static int IndexOf<T>(IEnumerable<T> collection, T target) 
    { 
     int i = 0; 
     foreach (var obj in collection) 
     { 
      if (obj.Equals(target)) 
       return i; 
      i++; 
     } 
     return -1; 
    } 

    private static int GroupIndexOf(IGrouping<object, DataPoint> group, DataPoint point) 
    { 
     int i = 0; 
     foreach (var pt in group) 
     { 
      if (pt == point) 
       return i; 
      i++; 
     } 

     return -1; 
    } 

    /// <summary> 
    /// Returns a value indicating whether this value can be graphed on a 
    /// linear axis. 
    /// </summary> 
    /// <param name="value">The value to evaluate.</param> 
    /// <returns>A value indicating whether this value can be graphed on a 
    /// linear axis.</returns> 
    private static bool CanGraph(double value) 
    { 
     return !double.IsNaN(value) && !double.IsNegativeInfinity(value) && !double.IsPositiveInfinity(value) && !double.IsInfinity(value); 
    } 

    /// <summary> 
    /// Converts an object into a double. 
    /// </summary> 
    /// <param name="value">The value to convert to a double.</param> 
    /// <returns>The converted double value.</returns> 
    private static double ToDouble(object value) 
    { 
     return Convert.ToDouble(value, CultureInfo.InvariantCulture); 
    } 


} 
1

Voici un code pour ajouter un comportement attaché à un ColumnSeries pour une commande SelectionChanged.

public static class ColumnSeriesBehavior 
{ 
    private static DelegateCommand<object> SelectionChangedCommand;  

    public static DelegateCommand<object> GetSelectionChangedCommand(ColumnSeries cs) 
    { 
     return cs.GetValue(SelectionChangedCommandProperty) as DelegateCommand<object>; 
    } 

    public static void SetSelectionChangedCommand(ColumnSeries cs, DelegateCommand<object> value) 
    { 
     cs.SetValue(SelectionChangedCommandProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for SelectionChangedCommand. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty SelectionChangedCommandProperty = 
     DependencyProperty.RegisterAttached("SelectionChangedCommand", typeof(DelegateCommand<object>), typeof(ColumnSeriesBehavior), new UIPropertyMetadata(null, OnSelectionChangedCommandChanged)); 

    private static void OnSelectionChangedCommandChanged(
     DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
    { 
     ColumnSeries item = depObj as ColumnSeries; 
     if (item == null) 
     {     
      return; 
     } 
     if (e.NewValue is DelegateCommand<object> == false) 
     { 

      return; 
     } 

     SelectionChangedCommand = e.NewValue as DelegateCommand<object>; 
     item.SelectionChanged += new System.Windows.Controls.SelectionChangedEventHandler(Column_SelectionChanged); 
    } 

    private static void Column_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) 
    { 
     if (SelectionChangedCommand != null) 
      SelectionChangedCommand.Execute(sender); 
    } 

} 

Et dans le XAML pour fixer la propriété:

<chartingToolkit:Chart.Series> 
      <chartingToolkit:ColumnSeries 
       IsSelectionEnabled="True"           
       ItemsSource="{Binding YourItemSource}" 
       IndependentValueBinding="{Binding YourIndValue, Path=YourIndValuePath}" 
       DependentValueBinding="{Binding YourDepValue, Path=YourDepValuePath}"           
       > 
       <chartingToolkit:ColumnSeries.Style> 
        <Style> 
         <!-- Attaching the SelectionChangedCommand behavior --> 
         <Setter Property="local:ColumnSeriesBehavior.SelectionChangedCommand" 
           Value="{Binding YourDelegateCommand}"/> 
        </Style> 
       </chartingToolkit:ColumnSeries.Style> 
      </chartingToolkit:ColumnSeries> 
     </chartingToolkit:Chart.Series> 
Questions connexes