代码之家  ›  专栏  ›  技术社区  ›  Jacob

如何在WPF工具包的图表控件中实现可命令的ColumnSeries

  •  1
  • Jacob  · 技术社区  · 15 年前

    我需要能够指定在SelectionChanged事件触发时运行的命令。我已经知道如何实现ICommandSource接口;我需要知道的是如何向列系列添加命令来处理SelectionChanged事件。

    当我从BarbaseSeries专栏继承时<&燃气轮机;基类我必须重写GetAxes()和UpdateDatePoint(),我不知道如何实现它们。

    3 回复  |  直到 15 年前
        1
  •  2
  •   Chris Nicol    15 年前

    您可以使用附加行为来解决此问题。

    创建SelectionChangedBehavior,将selectionChanged事件连接到要将行为附加到的元素,然后可以将任何ICommand绑定到该行为。

    有关附加行为的更多信息-

    希望有帮助

        2
  •  1
  •   Jacob    15 年前

    下面是一些代码,用于将附加行为添加到SelectionChanged命令的ColumnSeries中。

    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);
        }
    
    }
    

    在要附加属性的XAML中:

    <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>
    
        3
  •  0
  •   Jacob    15 年前

    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);
        }
    
    
    }