Create a WPF C# chart with Live Chart - c#

I Use Live Chart. SeriesCollection passes a Line Series in which Values = Chart Values. In xaml in Binding, I pass SeriesCollection. I understand that only y-points are transmitted (I do not change anything by default). How to transmit x points? Tried in ChartValue by index, swears that the index is empty. And even if you initially set the size of Chart Values, the cells that are not filled on the chart are filled as Y = 0. Please help, been three days sitting on it.
GenerateChart.cs:
public ChartValues<double> Points { get; set; }
double[] arraySeries = new double[30];
double[] array = new double[20];
public LineSeries GenerateSeries(string axis)
{
Random randomSeries = new Random();
ChartValues<double> series = new ChartValues<double>(new double[20]);
if (axis == "Y")
{
for (int i = 0; i < 5; i++)
{
double randomValue = randomSeries.Next(1, 20);
if (!array.Contains(randomValue))
{
array[i] = randomValue;
}
else
{
i--;
}
}
for (int i = 0; i < 5; i++)
{
double randomValue = randomSeries.Next(1, 20);
if (!arraySeries.Contains(randomValue))
{
int index = Convert.ToInt32(array[i]);
arraySeries[index] = randomValue;
}
else
{
i--;
}
}
for (int i = 0; i < 20; i++)
{
if (arraySeries[i] != 0)
{
series.Insert(i, arraySeries[i]);
}
}
//series.AddRange(arraySeries);
}
Points = series;
var testSeries = new LineSeries
{
Title = "Test",
Values = series
};
return testSeries;
}
RandomSeries.cs:
public SeriesCollection Series { get; private set; }
public SeriesCollection SeriesX { get; private set; }
public ChartValues<double> Points { get; private set; }
double[] arraySeries = new double[30];
double[] array = new double[20];
public SeriesCollection BuidChart()
{
Random randomSeries = new Random();
var generateChart = new GenerateChart();
Series = new SeriesCollection
{
generateChart.GenerateSeries("Y")
};
Points = generateChart.Points;
return Series;
}
ModelView.cs:
public SeriesCollection SeriesCollection { get; set; }
public ChartValues<double> Points { get; set; }
public RandomSeries randomSeries;
public Func<double, string> YFormatter { get; set; }
public string[] Labels { get; set; }
public SeriesCollection SeriesCollectionX { get; set; }
public void BuildFunction()
{
//Points.Clear();
//SeriesCollection.Clear();
randomSeries = new RandomSeries();
SeriesCollection = new SeriesCollection();
Points = new ChartValues<double>();
SeriesCollection.AddRange(randomSeries.BuidChart());
//Points.AddRange(randomSeries.Points);
//SeriesCollection.AddRange(randomSeries.BuidChart());
//Points.AddRange(randomSeries.Points);
Labels = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jan1", "Feb1", "Mar1", "Apr1", "May1" };
}
MainWindow.xaml:
<Window.DataContext>
<local:ModelView/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="257*"/>
<ColumnDefinition Width="536*"/>
</Grid.ColumnDefinitions>
<lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Right" Grid.ColumnSpan="2" Margin="0,0,-0.4,0" >
<!--<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Y" LabelFormatter="{Binding YFormatter}"></lvc:Axis>
</lvc:CartesianChart.AxisY>-->
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="X" Labels="{Binding Labels}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
Result program:
enter image description here

Ok in LiveChart there is possiblity to use ObservablePoint which represent X,Y position in the chart.
You need to add proper namespace to use these
using LiveCharts.Defaults;
I modfied two things in your Function, first I change definition and initialization of to ChartValues to by empty and typeof of ObservablePoint, so later we will dynamic fill these. You need also to change Points object to be type of ObservablePoint
ChartValues<ObservablePoint> series = new ChartValues<ObservablePoint>();
And also modified the filling of these series object to add only non-zero:
for (int i = 0; i < 20; i++)
{
if (arraySeries[i] != 0)
{
series.Add(new ObservablePoint(i, arraySeries[i]));
}
}
It will not draw zero-y-point between non-zero.

Related

How to use LiveCharts2 Zooming and Panning chart?

I would like to use LiveCharts2 Zooming and Panning chart in my project, but the given values does not shows up on the chart. I tried this code down below, but it is dos not solved my problem.
public ISeries[] SeriesCollection { get; set; }
public MainWindow()
{
InitializeComponent();
LoadDataToChart();
}
public void LoadDataToChart()
{
List<int> number = new List<int>();
Random rnd = new Random();
for (int i = 0; i < 100; i++)
{
number.Add(rnd.Next(0, 100));
}
SeriesCollection = new ISeries[] { new LineSeries<int> { Values = number } };

How do I get the sum or total of the prices of items inside my list box?

The button 1-10 are the items;
the pos screenshot
codes i used but doesn't work maybe it's wrong but i can't find answers on the internet
private void enterPayment_Click(object sender, EventArgs e)
{
label1.Text = "Payment";
//price.ReadOnly = false;
//price.Text = "0.00";
//price.Focus();
//Kukunin ko yung total ng List Items
double total = 0;
int ilan = orders.Items.Count;
for (int i = 0; i >= ilan; i++)
{
string item = orders.Items[i].ToString();
int Index = item.IndexOf("#");
int Length = item.Length;
string presyoString = item.Substring(Index + 1, Length - Index - 1);
double presyoDouble = double.Parse(presyoString);
total += presyoDouble;
//price.Text = (total + ".00");
}
price.Text = (total + ".00");
}
I strongly recommend that you use the listbox as a view only, not to be use to perform the mathematical operation. The data can be use in collection such as List so that you can perform better operation.
For example, at program load, I will add product information on List<T> and on form, I place a tag in the button consider it as product Id. So, when I click on the button, it will pass the tag property and from there, I will search the product information on list regarding my Id and add into another final List<T> and get the sum of it.
public partial class Form1 : Form
{
private List<ProductDisplay> listProductDisplay = new List<ProductDisplay>();
private List<ProductInformation> listProductInfo = new List<ProductInformation>();
public Form1()
{
InitializeComponent();
LoadProduct();
}
private void LoadProduct()
{
listProductDisplay = new List<ProductDisplay>()
{
new ProductDisplay{ProdID = 1,ProdName = "Chargrilled Burger",ProdPrice = 330.00m},
new ProductDisplay{ProdID = 2,ProdName = "Mushroom N' Swish",ProdPrice = 330.00m},
new ProductDisplay{ProdID = 3,ProdName = "Chicken Burger",ProdPrice = 250.00m},
new ProductDisplay{ProdID = 4,ProdName = "Steak Loader",ProdPrice = 220.00m},
new ProductDisplay{ProdID = 5,ProdName = "Cookie Sandwich",ProdPrice = 125.00m},
new ProductDisplay{ProdID = 6,ProdName = "Cookie Sundae",ProdPrice = 175.00m},
new ProductDisplay{ProdID = 7,ProdName = "Chicken Nuggets",ProdPrice = 145.00m},
new ProductDisplay{ProdID = 8,ProdName = "Curly Fries",ProdPrice = 75.00m},
new ProductDisplay{ProdID = 9,ProdName = "Sprite",ProdPrice = 50.00m},
new ProductDisplay{ProdID = 10,ProdName = "Coke",ProdPrice = 50.00m}
};
}
private void InsertOrder_ButtonClick(object sender, EventArgs e)
{
try
{
Button btn = (Button)sender;
int number = Convert.ToInt32(btn.Tag);
var itemProduct = listProductDisplay.First(x => x.ProdID == number);
ProductInformation prod = new ProductInformation
{
ProdID = itemProduct.ProdID,
ProdName = itemProduct.ProdName,
ProdPrice = itemProduct.ProdPrice,
ProdQty = 1
};
prod.ProdDisplayName = $"{prod.ProdQty}x {prod.ProdName} #{prod.ProdPrice.ToString("F")} = {(prod.ProdPrice * prod.ProdQty).ToString("F")}";
listProductInfo.Add(prod);
listBoxItem.DataSource = null;
listBoxItem.DataSource = listProductInfo;
listBoxItem.DisplayMember = "ProdDisplayName";
listBoxItem.ValueMember = "ProdID";
var price = listProductInfo.Sum(t => (t.ProdPrice * t.ProdQty));
txtPayment.Text = price.ToString("F");
}
catch (Exception ex)
{
MessageBox.Show("Failed to insert order");
throw;
}
}
}
public class ProductDisplay
{
public int ProdID { get; set; }
public string ProdName { get; set; }
public decimal ProdPrice { get; set; }
}
public class ProductInformation
{
public int ProdID { get; set; }
public string ProdName { get; set; }
public string ProdDisplayName { get; set; }
public decimal ProdPrice { get; set; }
public int ProdQty { get; set; }
}
Parsing and extracting values from a string like that is very error prone and brittle. What happens if the order of fields in your line changes? Or if you add currency symbols?
#Luiey's solution is the smartest way to go ahead. But if for some reason you cannot make so many changes to your code, the bare minimum you want to do is store the items in a list as a custom object with statically typed fields for price, quantity and total. The ListBox class invokes a ToString() at the time of rendering items. So you can easily override this method to prepare the output string according to your needs.
private class LineItem
{
public LineItem()
{
Quantity = 0;
Description = string.Empty;
Price = 0;
}
public int Quantity
{
get;
set;
}
public string Description
{
get;
set;
}
public int Price
{
get;
set;
}
public int Total
{
get
{
return Quantity * Price;
}
}
public override string ToString()
{
return $"{Quantity} × {Description} # {Price} = {Total}";
}
}
Then you add an item to your ListBox like this.
var item = new LineItem()
{
Quantity = 1,
Description = "Foo bar",
Price = 10
};
listBox1.Items.Add(item);
And add them up like this.
var items = listBox1.Items.Cast<LineItem>().ToArray();
var accumulator = 0;
accumulator = items.Aggregate(accumulator, (a, i) => a + (i.Quantity * i.Price), (a) => a);

adding list array into datagrid column

I have made a code which makes few lists. In the end i get the following lists:
List<int> list_AmountNeed = new List<int>();
List<int> list_TotalCost = new List<int>();
List<int> list_TotalLose = new List<int>();
List<int> list_TotalGain = new List<int>();
after few calculations these lists contain values (24 in each if it matter):
while (z < list_Exp.Count)
{
list_AmountNeed.Add((goalexp - currentexp) / Convert.ToInt32(list_Exp[z]));
list_TotalLose.Add(list_AmountNeed[z] * (list_Amount_MadeFrom_One[z] * list_BuyPrice_MadeFrom_One[z] + list_Amount_MadeFrom_Two[z] * list_BuyPrice_MadeFrom_Two[z]));
list_TotalGain.Add(list_AmountNeed[z] * list_AmountMade[z] * list_SellPrice[z]);
list_TotalCost.Add(list_TotalGain[z] - list_TotalLose[z]);
z++;
}
Now, i have made a UI containing a button and Datagrid using blend and i want those lists to be shown in the Datagrid columns once i click the button.
what i did so far is inserting this code into the button xaml.cs.
the thing im not sure how to do is if i can write the displaying code inside the button xaml.cs or it have to be in the datagrid and whats the right code to show it in columns:
column 1:
list_AmountNeed
column 2:
list_TotalCost
and so on.
Thank you!
4 lists to store related data is a bad data structure (definitely not OOP). E.g. to add 1 piece of data ({amount,cost,lose,gain}) one have to perform 4 Add operations.
also DataGrid displays data row-wise so one cannot just go and display independent lists in different columns.
DataTable (suggested by #rory.ap) is an excellent general-purpose class and works fine with DataGrid but I would say it is too much for current requirement.
Let's instead create a POCO with 4 properties and a list of those objects with real values and display them in a DataGrid.
public class MyDataObject
{
public int Amount { get; set; }
public int Cost { get; set; }
public int Lose { get; set; }
public int Gain { get; set; }
}
window content xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Button Content="+" Click="DisplayClick"/>
<DataGrid Name="Dg" Grid.Row="1"/>
</Grid>
window code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private List<MyDataObject> L = new List<MyDataObject>
{
new MyDataObject {Amount = 1, Cost = 1, Gain = 1},
new MyDataObject {Amount = 2, Cost = 2, Gain = 4},
new MyDataObject {Amount = 3, Cost = 3, Gain = 9},
};
private void DisplayClick(object sender, RoutedEventArgs e)
{
Dg.ItemsSource = L;
}
}
When ItemsSource is assigned, DataGrid generates a column for each property (property name is displayed in a header) and create bindings between columns and properties
result:
if necessary extend MyDataObject with additional properties, e.g.
public class MyDataObject
{
public int SellPrice {get; set; }
public int Amount { get; set; }
public int Cost { get; set; }
public int Lose { get; set; }
public int Gain { get; set; }
}
calculation method can be modified to use MyDataObject objects
var L = new List<MyDataObject>();
for(int z = 0; z < list_Exp.Count; z++)
{
var d = new MyDataObject();
d.Amount = (goalexp - currentexp) / Convert.ToInt32(list_Exp[z]);
d.Lose = d.Amount * (list_Amount_MadeFrom_One[z] * list_BuyPrice_MadeFrom_One[z] + list_Amount_MadeFrom_Two[z] * list_BuyPrice_MadeFrom_Two[z]);
// d.SellPrice = list_SellPrice[z];
d.Gain = d.Amount * list_AmountMade[z] * list_SellPrice[z];
d.Cost = d.Gain - d.Lose;
L.Add(d);
}
Very similar to ASh, using the same principles. My datagrid is in a Winform, but you can perform the same operations on your XAML datagrid.
using System.Collections.Generic;
using System.Windows.Forms;
namespace PopulatingDataGridColumns_42584334
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
List<int> list_AmountNeed = new List<int>() { 3, 6, 7, 8, 9, 12 };
List<int> list_TotalCost = new List<int>() { 4, 3, 6, 9, 65, 87 };
List<int> list_TotalLose = new List<int>() { 7, 9, 2, 5, 15, 27 };
List<int> list_TotalGain = new List<int>() { 3, 1, 2, 2, 0, 4 };
List<gridviewdata> mydatalist = new List<gridviewdata>();
for (int i = 0; i < list_AmountNeed.Count; i++)
{
mydatalist.Add(new gridviewdata
{
col1 = list_AmountNeed[i].ToString(),
col2 = list_TotalCost[i].ToString(),
col3 = list_TotalLose[i].ToString(),
col4 = list_TotalGain[i].ToString()
});
}
dataGridView1.DataSource = mydatalist;//assuming the datagridview is named dataGridView1
}
}
class gridviewdata
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
public string col4 { get; set; }
}
}

Load a list from an array

I have a program that is working except that my data is contained in an array; however, I have found out from you people that I cannot load a dataGridView from an array.
If I had code like this, how would I load a List for the source of the dataGridView1...
// Load some date to indicate what I'm trying to do.
int nColName = 0;
int nColNumberOfOccurances = 1;
int nColTotalTime = 2;
int nColAverageTime = 3;
string[,] strMyArray = new string[2,4];
// load array with test data
for (int i = 0; i < strMyArray.Length; i++)
{
switch (i)
{
case 0:
strMyArray.SetValue("file1.log".ToString(), i, nColName);
strMyArray.SetValue("10".ToString(), i, nColNumberOfOccurances);
strMyArray.SetValue("8989".ToString(), i, nColTotalTime);
strMyArray.SetValue("898.9".ToString(), i, nColAverageTime);
break;
case 1:
strMyArray.SetValue("file2.log".ToString(), i, nColName);
strMyArray.SetValue("5".ToString(), i, nColNumberOfOccurances);
strMyArray.SetValue("4494.5".ToString(), i, nColTotalTime);
strMyArray.SetValue("898.9".ToString(), i, nColAverageTime);
break;
}
}
// convert an array like the above into a List so that I can say...
// myNewListFromArray = strMyArray
// dataGridView1.DataSource = myNewListFromArray;
Arrays works with DataGridView. Your problems is - you using two dimensional array which cannot be used as DataSource.
Instead of array, create a class with properties which represent your data.
Note: important to use a property, because DataGridView binding works with properties only.
public class MyData
{
public string Name { get; set; }
public string NumberOfOccurances { get; set; }
public string TotalTime { get; set; }
public string AverageTime { get; set; }
}
Then use this class in the List
var list = new List<MyData>
{
new MyData
{
Name = "file1.log",
NumberOfOccurances = "10",
TotalTime = "8989",
AverageTime = "898.9"
},
new MyData
{
Name = "file2.log",
NumberOfOccurances = "5",
TotalTime = "4494.5",
AverageTime = "898.9"
},
}
dataGridView1.DataSource = list;

How store From-To value and result in an array

I want to store some items with fields "fromValue", "ToValue" , "Info" in an array and write a routine to search an input "value" between "FromValue" & "ToValue" and return "Info" field. I need fast searchable container.
FromValue,ToValue,Info
10,20,TX
24,56,NY
input =34 returns NY
Thanks
ok simple, this class defines your generic range.
public class Range<TValue, TInfo>
{
private readonly IComparer<TValue> comparer;
public Range(IComparer<TValue> comparer)
{
this.comparer = comparer;
}
public Range(IComparer<TValue> comparer)
: this(Comparer<TValue>.Default)
{
}
public TValue From { get; set; }
public TValue To { get; set; }
public TInfo Info { get; set; }
public bool InRange(T value, bool inclusive = true)
{
var lowerBound = this.comparer.Compare(value, this.From);
if (lowerBound < 0)
{
return false;
}
else if (!inclusive && lowerBound == 0)
{
return false;
}
var upperBound = this.comparer.Compare(value, this.To);
if (upperBound > 0)
{
return false;
}
else if (!inclusive && upperBound == 0)
{
return false;
}
return true;
}
}
So, you can have a sequence of ranges,
IEnumerable<Range<int, string>> ranges = ...
To find all the info values in range you can do,
var rangesInRange = ranges.Where(r => r.InRange(42)).Select(r => r.Info);
You could make a specialised container to improve this operation.
Class:
public class Information
{
public int FromValue { get; set; }
public int ToValue { get; set; }
public string Info { get; set; }
}
Search:
List<Information> Informations = new List<Information>();
Information infoObj = new Information();
infoObj.FromValue = 10;
infoObj.ToValue = 20;
infoObj.Info = "TX";
Informations.Add(infoObj);
Information infoObj2 = new Information();
infoObj2.FromValue = 24;
infoObj2.ToValue = 56;
infoObj2.Info = "NY";
Informations.Add(infoObj);
//passing sample input which lies between fromvalue and tovalue
int sampleInput = 15;
var result = Informations.FirstOrDefault(x => x.FromValue < sampleInput && sampleInput < x.ToValue);
This is pretty straight forward.
In the most simple scenario just create a class Item
public class Item
{
public int Id { get; set; }
public int FromValue { get; set; }
public int ToValue { get; set; }
public string Info { get; set; }
}
With this you can initialize your collection of type List<T>
List<Item> Items = new List<Item>()
{
new Item() {Id = 1, FromValue = 10, ToValue = 20, Info = "TX"}
new Item() {Id = 2, FromValue = 24, ToValue = 56, Info = "NY"}
new Item() {Id = 3, FromValue = 15, ToValue = 34, Info = "FL"}
};
And with this you can query it to your hearts content.
var itemsFromFlorida = Items.Where(it => it.Info == "FL");

Categories

Resources