본문 바로가기
카테고리 없음

[C# WPF] Bar Chart in WPF

by YJHTPII 2023. 7. 20.
반응형

 

 

https://www.c-sharpcorner.com/UploadFile/mahesh/bar-chart-in-wpf/

 

Bar Chart in WPF

This article demonstrates how to draw bar charts in WPF and C#.

www.c-sharpcorner.com

 

 

 

 

 

 

Creating a Chart
 
The Chart element represents a WPF Chart control in XAML.
  1. < DVC:Chart></DVC:Chart>  
The code snippet in Listing 1 creates a Chart and sets its width, height, and background properties of the Chart control. The Title and LegendTitle properties represent the title of the chart and the title of legend.
  1. <DVC:Chart Name="mcChart"  
  2. Width="400" Height="250"  
  3. Background="YellowGreen"  
  4. Foreground="DarkBlue"  
  5. Title="Area Chart"  
  6. LegendTitle="Month Rating" />  
Listing 1
 
The output of Listing 1 looks like Figure 5.

 

Figure 5
 
Chart Types
 
The Series attribute of the Chart element is used to create a chart type. If you see in Figure 6, you will notice BarSeries, ColumnSeries, LineSeries, PieSeries, AreaSeries and ScatterSeries attributes and based on the attribute, the chart will be created.
 
Figure 6
 
Bar Chart
 
The code snippet in Listing 2 creates a bar chart by setting Chart.Series to BarSeries. As you see, the binding is occurred on Key and Value fields of a data source. 
  1. <DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart"
  2.            Width="400" Height="250"
  3.            Background="LightSteelBlue">
  4.     <DVC:Chart.Series>
  5.         <DVC:BarSeries Title="Experience"    
  6.             IndependentValueBinding="{Binding Path=Key}"
  7.             DependentValueBinding="{Binding Path=Value}"> 
  8.         </DVC:BarSeries>
  9.      </DVC:Chart.Series>  
  10. </DVC:Chart>
Listing 2
 
The code snippet in Listing 3 creates a collection in KeyValuePair form and sets the ItemsSource property of the chart series. Same data can be used for other chart types.
  1. private void LoadBarChartData()    
  2. {    
  3.     ((BarSeries)mcChart.Series[0]).ItemsSource =    
  4.         new KeyValuePair<stringint>[]{    
  5.             new KeyValuePair<stringint>("Project Manager", 12),    
  6.             new KeyValuePair<stringint>("CEO", 25),    
  7.             new KeyValuePair<stringint>("Software Engg.", 5),    
  8.             new KeyValuePair<stringint>("Team Leader", 6),    
  9.             new KeyValuePair<stringint>("Project Leader", 10),    
  10.             new KeyValuePair<stringint>("Developer", 4) };    
  11. }   
Listing 3
 
The output looks like Figure 7.
 
 
 Figure 7
 
Generating a Bar Chart from a Collection
 
Now we are going to generate a bar chart from a collection. I have a class Fruit that looks like Listing 4. It has two members Name and Share.
  1. class Fruit    
  2. {    
  3.     public string Name { getset; }    
  4.     public Int16 Share { getset; }    
  5. }   
Listing 4
 
Listing 5 is a Fruit collection class that adds some Fruit objects in the constructor.
  1. class FruitCollection : System.Collections.ObjectModel.Collection<Fruit>    
  2. {    
  3.     public FruitCollection()    
  4.     {    
  5.         Add(new Fruit { Name = "Mango", Share = 10 });    
  6.         Add(new Fruit { Name = "Banana", Share = 36 });    
  7.         Add(new Fruit { Name = "Apple", Share = 24 });    
  8.         Add(new Fruit { Name = "Guava", Share = 4 });    
  9.         Add(new Fruit { Name = "Orange", Share = 12 });    
  10.         Add(new Fruit { Name = "Pear", Share = 10 });    
  11.         Add(new Fruit { Name = "Pineapple", Share = 4 });    
  12.     }    
  13. }   
Listing 5
 
Now in our XAML code, I create a resource called FruitCollection and bind it to the PieSeries using the ItensSource property as listed in Listing 6.
  1. <Grid.Resources>  
  2.     <local:FruitCollection x:Key="FruitCollection" />  
  3. </Grid.Resources>   
  4.   
  5. <DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart"  
  6.    Width="400" Height="250"  
  7.    Background="LightSteelBlue">  
  8.     <DVC:Chart.Series>  
  9.         <DVC:PieSeries Title="Fruits"  
  10.             ItemsSource="{StaticResource FruitCollection}"  
  11.             IndependentValueBinding="{Binding Path=Name}"  
  12.             DependentValueBinding="{Binding Path=Share}">  
  13.         </DVC:PieSeries>  
  14.     </DVC:Chart.Series>  
  15. </DVC:Chart>    

 

Listing 6
 
Now simply build and run the project. New output looks like Figure 8.
 
 
Figure 8
 
Summary
 
This article demonstrated how to create bar charts in WPF using WPF Toolkit.
 
 
 
 
 
 
 
 
 

Creating a Chart in WPF

This article describes how to create a chart in WPF.

www.codeproject.com

 

 

 

Introduction

This article shows how to make great looking charts in WPF. For demonstration of this, I have developed a WPF Project using Visual C# 2010 Express Edition. This project displays population of the top 5 most populous countries of the world using a column chart.

Background

Chart functionality in WPF is provided by the WPF Toolkit assembly. A reference to the System.Windows.Controls.DataVisualization.Toolkit.dll file is added to the project. Then the System.Windows.Controls.DataVisualization.Charting namespace is imported in the page as follows:

XML
 
xmlns:cht="clr-namespace:System.Windows.Controls.DataVisualization.Charting;
assembly=System.Windows.Controls.DataVisualization.Toolkit" 

Using the Code

To provide data for the chart, the following class is created:

C#
 
public class Country
{
    public Country(string Name, long Population)    // Constructor
    {
        this.Name = Name;
        this.Population = Population;
    }
    public string Name                // Name Property
    {
        get;
        set;
    }
    public long Population                // Population Property
    {
        get;
        set;
    }
}

The following class represents the list of top 5 most populous countries:

C#
 
public class CountryCollection :
Collection<Country> // Extending from System.Collections.ObjectModel.Collection class
{
    public CountryCollection() // Constructor to add Country objects to the CountryCollection
    {
        Add(new Country("China", 1336718015));
        Add(new Country("India", 1189172906));
        Add(new Country("United States", 313232044));
        Add(new Country("Indonesia", 245613043));
        Add(new Country("Brazil", 203429773));
    }
}

Next a resource called CountryCollection is created in the XAML code as follows:

XML
 
<Window.Resources>
    <local:CountryCollection x:Key="CountryCollection"/>
</Window.Resources>

Following is the XAML code for the Chart control:

XML
 
<cht:Chart Name="populationChart" Title="Top 5 Most Populous Countries of the World" 
    Background="LightBlue">
     <cht:Chart.Series>
         <cht:ColumnSeries Title="Population" 
    ItemsSource="{StaticResource CountryCollection}" 
    IndependentValueBinding="{Binding Path=Name}" 
    DependentValueBinding="{Binding Path=Population}">
         </cht:ColumnSeries>
     </cht:Chart.Series>
</cht:Chart>

In the above code, the CountryCollection resource is bound to the ColumnSeries using the
ItemsSource property. The IndependentValueBinding property binds the country name and
DependentValueBinding property binds the population.

Following is the complete XAML code for the application:

XML
 
<Window x:Class="WPFPopulationChart.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFPopulationChart"
        xmlns:cht="clr-namespace:System.Windows.Controls.
        DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
        Title="Population Chart" Height="350" Width="525">
    <Window.Resources>
        <local:CountryCollection x:Key="CountryCollection"/>
    </Window.Resources>
    <Grid>
        <cht:Chart Name="populationChart"
        Title="Top 5 Most Populous Countries of the World" Background="LightBlue">
            <cht:Chart.Series>
                <cht:ColumnSeries Title="Population"
                ItemsSource="{StaticResource CountryCollection}"
                IndependentValueBinding="{Binding Path=Name}"
                DependentValueBinding="{Binding Path=Population}">
                </cht:ColumnSeries>
            </cht:Chart.Series>
        </cht:Chart>
    </Grid>
</Window>

Points of Interest

Population data for the chart is taken from the following link:

The population figures are as on December 2011.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

 

 

 

 

WPF Bar Chart as simple as possible

 

https://www.codeproject.com/Tips/720042/WPF-Bar-Chart-as-simple-as-possible

 

WPF Bar Chart as simple as possible

Creating a bar chart with most of needed features.

www.codeproject.com

 

 

 

Creating a bar chart with most of needed features.

Introduction

Most of User controls in WPF are heavy to load, specially when we use them inside another control(e.g. DataGrid). If we use a DataGrid, Chart or another control inside the rows details in DataGrid, it makes our form's loading too slow. Because of that,I decided to create a light weight BarChart control to decrease this problem.

In this control we can bind items and legends to it's ItemsSource property. There are 3 properties to introducing horizontal, vertical and legends properties in Item source to chart, : HorizontalPropertyName, VerticalPropertyName and LegendPropertyName.

In additional of this, we can change some appearance parameters such as changing visibility of Values labels and Legends list, and manipulating legends header and color.

Using the code

In control's class, Draw() method creates our view by using our ItemsSource or Items properties. In some events we call this method to refresh our view. This method creates a Border control per each information, then locates that on a canvas by calculating its location. For calculating our drawing area and borders, we use count of legends and horizontal values. Borders width dynamically changes by control width and count of legends.

Our second main method is GetLegends(). By using this method we can fetch all of legends by there property name declared in LegendPropertyName property.

 

C#
Shrink ▲   
private void GetLegends()
{
    if (Legends == null)
        Legends = new ObservableCollection<Legend>();
 
    if (Items == null)
        return;
 
    Random rand = new Random(DateTime.Now.Millisecond);
    foreach (var item in Items)
    {
        var LegValue = item.GetType().GetProperty(LegendPropertyName).GetValue(item, null);
 
        var leg = from Legend lc in Legends where lc.LegendType.Equals(LegValue) select lc;
        if (leg.Count() == 0)
        {
             Legend legend = new Legend();
             legend.LegendType = LegValue;
             Color c = Color.FromRgb(Convert.ToByte(rand.Next(256)), Convert.ToByte(rand.Next(256)), Convert.ToByte(rand.Next(256)));
             legend.Color = new SolidColorBrush(c);
             legend.IsVisibleChanged += (s, e) =>
                    {
                        Draw(false);
                    };
 
             Legends.Add(legend);
        }
        else
        leg.First().IsVisibleChanged += (s, e) =>
        {
             Draw(false);
        };
    }
} 

 

For declaring legends and changing there property, I defined a class with name Legend that inherits from DependencyObject and INotifyPropertyChanged. We have some properties(LegendType, DisplayName, Color and IsVisible) and one event(IsVisibleChanged) in this class.

C#
Shrink ▲   
public class Legend : DependencyObject, INotifyPropertyChanged
    {
        #region Constructors
        public Legend()
        {
        }
        #endregion Constructors
 
        #region Properties
        private object _legend = null;
        public object LegendType
        {
            get { return _legend; }
            set
            {
                _legend = value;
                Notify("Legend");
            }
        }
 
        private string _displayName = String.Empty;
        public string DisplayName
        {
            get
            {
                if (String.IsNullOrEmpty(_displayName))
                    if (LegendType == null)
                        return String.Empty;
                    else
                        return LegendType.ToString();
                else
                    return _displayName;
            }
            set
            {
                _displayName = value;
                Notify("DisplayName");
            }
        }
 
        private Brush _color = null;
        public Brush Color
        {
            get { return _color; }
            set
            {
                _color = value;
                Notify("Color");
            }
        }
 
        private bool _isVisible = true;
        public bool IsVisible
        {
            get { return _isVisible; }
            set
            {
                if (_isVisible != value)
                {
                    _isVisible = value;
                    Notify("IsVisible");
                    if (IsVisibleChanged != null)
                        IsVisibleChanged(this, new RoutedEventArgs());
                }
            }
        }
        #endregion Properties
 
        #region Events
        public event RoutedEventHandler IsVisibleChanged;
        #endregion Events
 
        #region Methods
        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
        #endregion Methods
    } 

For using this control we can declare a class or structure for passing main properties to it and use them to draw bars. For example, I declared a simple class to do this.

C#
 
public class MyData
   {
       public MyData()
       {
       }

       public int Year { get; set; }

       public double Value { get; set; }

       public WorkTypes WorkType { get; set; }
   }

And an Enum to indicate my legends.

C#
 
public enum WorkTypes
   {
       Buy,
       Sell,
       Receipt,
       Draft
   }

By using a List, ArrayList, ObservableCollection or other classes inherited from IEnumerable, we can create an array of our class and pass that to controls Items property or bind that to ItemsSource property.

XML
 
<controls:BarChart x:Name="BarChart1"
                   LegendPropertyName="WorkType"
                   VerticalPropertyName="Value"
                   HorizontalPropertyName="Year"
                   FontFamily="Tahoma"
                   ItemsSource="{Binding Path=Data,
                                 RelativeSource={RelativeSource AncestorType=Window}}">

In above code, I passed "WorkType" to LegendPropertyName, "Value" to VerticalPropertyName and Year to HorizontalPropertyName to use this names for accessing value of this properties in my class. For presenting my information in chart, I binded Data property in my class to ItemsSource property of control.

For customizing legends, User can change their attributes and properties. Some thing like this :

XML
Shrink ▲   
<controls:BarChart.Legends>
     <controls:Legend DisplayName="Buy" LegendType="{x:Static my:WorkTypes.Buy}">
          <controls:Legend.Color>
               <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                     <GradientStop Color="#FF5C8EFF" Offset="0" />
                     <GradientStop Color="#FFC2C2FC" Offset="1" />
               </LinearGradientBrush>
          </controls:Legend.Color>
     </controls:Legend>
     <controls:Legend DisplayName="Sell" LegendType="{x:Static my:WorkTypes.Sell}">
          <controls:Legend.Color>
               <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                    <GradientStop Color="#FF63B700" Offset="0" />
                    <GradientStop Color="#FFBDEB94" Offset="1" />
               </LinearGradientBrush>
          </controls:Legend.Color>
     </controls:Legend>
     <controls:Legend DisplayName="Receipt" LegendType="{x:Static my:WorkTypes.Receipt}">
          <controls:Legend.Color>
               <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                     <GradientStop Color="#FFA9B700" Offset="0" />
                     <GradientStop Color="#FFEBEB94" Offset="1" />
               </LinearGradientBrush>
          </controls:Legend.Color>
     </controls:Legend>
     <controls:Legend DisplayName="Draft" LegendType="{x:Static my:WorkTypes.Draft}">
          <controls:Legend.Color>
               <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                      <GradientStop Color="#FFB700B7" Offset="0" />
                      <GradientStop Color="#FFD794EB" Offset="1" />
               </LinearGradientBrush>
          </controls:Legend.Color>
     </controls:Legend>
</controls:BarChart.Legends>

Points of Interest

In this control, I used dynamic property names for my first time. With dynamic property names, we can improve control's flexibility and use controls in every forms and projects without needing any [large] changes.

Finally

I hope this code and this user control help you to creating new controls.

I apologies for my poor description because of my weak English knowledge.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

반응형

댓글