I want to add a dynamic micro chart to my application but it doesn't work. After a call from a method a value gets added and it makes a completely new micro chart for my chart to have the new values, but the change isn't visible in the app. So the old Values stayed and there is no new one. Thanks for helping me.
WeightList = new List<float>();
WeightList.Add(0);
WeightList.Add((float)74.3);
entries = new ChartEntry[30];
SyncArray();
private void SyncArray()
{
if (WeightList.Count != entries.Length)
{
entries = new ChartEntry[WeightList.Count];
}
for (int i = 0; i <= WeightList.Count - 1; i++)
{
if (i == WeightList.Count - 1 || i == 0)
{
entries[i] = new ChartEntry(WeightList[i]) { Label = "" + i, ValueLabel = "" + WeightList[i] };
}
else
{
entries[i] = new ChartEntry(WeightList[i]) { Label = "" + i };
}
}
chart = new LineChart() { Entries = entries, BackgroundColor = SKColors.Transparent };
Chart = chart;
}
public LineChart Chart
{
get => chart;
set => SetProperty(ref chart, value);
}
public float Weight
{
get => weight;
set
{
weight = value;
WeightList.Add(weight);
SyncArray();
}
}
Credits: #Jason
What to change:
private void SyncArray()
{
if (WeightList.Count != entries.Length)
{
entries = new ChartEntry[WeightList.Count];
}
for (int i = 0; i <= WeightList.Count - 1; i++)
{
if (i == WeightList.Count - 1 || i == 0)
{
entries[i] = new ChartEntry(WeightList[i]) { Label = "" + i, ValueLabel = "" + WeightList[i] };
}
else
{
entries[i] = new ChartEntry(WeightList[i]) { Label = "" + i };
}
}
Chart = new LineChart() { Entries = entries, BackgroundColor = SKColors.Transparent };
}
Related
My goal is to create a chart that will sit inside of a panel restricting it's size.
I managed to achieve this some time ago but today I noticed that the chart was growing inside of the panel, not allowing the data to be seen.
I have attached a picture bellow which should help understand the issue.
UPDATE
I noticed that if I rmeove 'bottom' from the Anchor property of the panel the chart does not exceed the parent panel but it does not increase with the change of the form which is what I'm looking for.
I also noticed that there was also another chart on the form that was exceeding the parent form, this time the chart would extend to the right not allowing to see the data.
This is the code that generates this second chart and places is inside of the parent panel.
panel_chart.Controls.Clear();
chart1 = new Chart();
chart1.MouseMove += chart1_MouseMove;
chart1.ChartAreas.Add(new ChartArea("chartArea1"));
chart1.Series.Clear();
chart1.Titles.Clear();
var serieOEE = new Series("OEE");
serieOEE.ChartType = SeriesChartType.Line;
serieOEE.XValueType = ChartValueType.String;
var serieProd = new Series("Prod");
serieProd.ChartType = SeriesChartType.Column;
serieProd.XValueType = ChartValueType.String;
var serieDisp = new Series("Disp");
serieDisp.ChartType = SeriesChartType.Column;
serieDisp.XValueType = ChartValueType.String;
var serieQual = new Series("Qual");
serieQual.ChartType = SeriesChartType.Column;
serieQual.XValueType = ChartValueType.String;
DateTime DataReg = DateTime.MinValue;
List<AreaOEE> listaChart = new List<AreaOEE>();
foreach (var item in ListaGrafico) //listaOEE
{
if (item.Designacao == DesignacaoLista)
{
listaChart.Add(item);
}
}
listaChart = listaChart.OrderBy(a => a.IDReg).ToList();
DateTime DataUltimoReg = DateTime.MinValue;
int j = 0;
foreach (var item in listaChart)
{
string HoraGraf = Convert.ToDateTime(item.Hora).ToString("HH:mm");
if (j == 0 || j == listaChart.Count - 1 ||
Math.Abs(Convert.ToDateTime(item.Hora).Subtract(DataUltimoReg).TotalMinutes) >= 30)
{
serieOEE.Points.AddXY(HoraGraf, item.OEE);
serieProd.Points.AddXY(HoraGraf, item.Produtividade);
serieQual.Points.AddXY(HoraGraf, item.Qualidade);
serieDisp.Points.AddXY(HoraGraf, item.Disponibilidade);
DataUltimoReg = Convert.ToDateTime(item.Hora);
if (j == listaChart.Count - 2)
{
break;
}
}
j++;
}
//Adicionar o ultimo
foreach (var item in listaOEE)
{
if (item.Designacao == DesignacaoLista)
{
string sHora = "";
try
{
sHora = item.Hora.Substring(1, 5);
}
catch (Exception ex)
{
string sEx = ex.Message;
}
foreach (var itemOee in serieOEE.Points)
{
if (itemOee.AxisLabel == sHora)
{
itemOee.YValues[0] = item.OEE;
}
}
foreach (var itemP in serieProd.Points)
{
if (itemP.AxisLabel == sHora)
itemP.YValues[0] = item.Produtividade;
}
foreach (var itemD in serieDisp.Points)
{
if (itemD.AxisLabel == sHora)
itemD.YValues[0] = item.Disponibilidade;
}
foreach (var itemQ in serieQual.Points)
{
if (itemQ.AxisLabel == sHora)
itemQ.YValues[0] = item.Qualidade;
}
}
}
chart1.Series.Add(serieProd);
chart1.Series.Add(serieQual);
chart1.Series.Add(serieDisp);
chart1.Series.Add(serieOEE);
serieOEE.BorderWidth = 4;
chart1.ChartAreas[0].AxisX.LabelStyle.Angle = 90;
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 140;
chart1.Legends.Clear();
chart1.Legends.Add(serieOEE.Legend);
chart1.Titles.Add(DesignacaoLista + " " + DataTitulo.ToString("dd-MM HH:mm"));
chart1.Titles[0].Font = new Font("Arial", 13, FontStyle.Bold);
chart1.Visible = true;
chart1.Dock = DockStyle.Fill;
panel_chart.Controls.Add(chart1);
you can change the size of Chart with Chart.Size:
Chart1.Size = new Size(1000, 200); //1000px * 200px
I am able to get the 0 as value. However I want to set a descriptive text like B does not have any data and similar is the case for D here in the chart.
I want to have text whenever a company does not have any value which is 0 in this case. This can happen for multiple companies so how can I automate this?
I am using this to put category data-Sample code
DocumentFormat.OpenXml.Drawing.Charts.CategoryAxisData categoryAxisData1 = new DocumentFormat.OpenXml.Drawing.Charts.CategoryAxisData();
C.StringReference stringReference2 = new C.StringReference();
C.Formula formula2 = new C.Formula
{
Text = "Sheet1!$A$2:$A$7"
};
C.StringCache stringCache2 = new C.StringCache();
C.PointCount pointCount2 = new C.PointCount() { Val = Convert.ToUInt32(companies.Count) };
stringCache2.Append(pointCount2);
int count = 0;
for (int i = companies.Count-1; i >= 0 ; i--)
{
C.StringPoint stringPoint = new C.StringPoint() { Index = Convert.ToUInt32(count) };
C.NumericValue numericValue = new C.NumericValue
{
Text = companies[i].CompanyName
};
stringPoint.Append(numericValue);
stringCache2.Append(stringPoint);
count++;
}
stringReference2.Append(formula2);
stringReference2.Append(stringCache2);
categoryAxisData1.Append(stringReference2);
Sample code for value on barchart-
C.Values values1 = new C.Values();
C.NumberReference numberReference1 = new C.NumberReference();
C.Formula formula3 = new C.Formula
{
Text = "Sheet1!$B$2:$B$7"
};
C.NumberingCache numberingCache1 = new C.NumberingCache();
C.FormatCode formatCode1 = new C.FormatCode
{
Text = "General"
};
numberingCache1.Append(formatCode1);
C.PointCount pointCount3 = new C.PointCount() { Val = Convert.ToUInt32(companies.Count) };
numberingCache1.Append(pointCount3);
for (int i = 0; i < companies.Count; i++)
{
C.NumericPoint numericPoint = new C.NumericPoint() { Index = Convert.ToUInt32(i) };
//C.NumericValue numericValue = new C.NumericValue
//{
// Text = (sliderValueForComapnies[i] > 0) ? sliderValueForComapnies[i].ToString() : "Data not avaialble",
//};
C.NumericValue numericValue = new C.NumericValue();
if (sliderValueForComapnies[i] > 0)
{
numericValue.Text = sliderValueForComapnies[i].ToString();
}
//else
//{
// this area will have the companies with 0 as value so what can I do here to add text?
//}
numericPoint.Append(numericValue);
numberingCache1.Append(numericPoint);
}
numberReference1.Append(formula3);
numberReference1.Append(numberingCache1);
values1.Append(numberReference1);
I have a class like this:
public class PricingRecord
{
private string _name;
private float[] _prices;
public PricingRecord(string name, float[] prices)
{
_name = name;
_prices = prices;
}
[DisplayName("Name")]
public string PricingName => _name;
public float[] Prices => _prices;
}
I want to map "Prices" to "Price 1", "Price 2", etc. columns in a DataGridView. I can get the columns to appear, but don't know how to make the mapping work.
Here's the main window:
public partial class MainForm : Form
{
private int _numPricingColumns;
private BindingList<PricingRecord> _records;
public MainForm()
{
InitializeComponent();
SetupPricingData();
SetupGridView();
}
private void SetupPricingData()
{
_records = new BindingList<PricingRecord>();
for (int i = 0; i < 100; i++)
{
var pricing = new PricingRecord($"Name {i + 1}", new [] { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f });
_records.Add(pricing);
}
_numPricingColumns = _records[0].Prices.Length;
GridView.DataSource = _records;
}
private void SetupGridView()
{
//GridView.AutoGenerateColumns = false;
//DataGridViewColumn column = new DataGridViewTextBoxColumn
//{
// Name = "Name",
// DataPropertyName = "PricingName"
//};
//GridView.Columns.Add(column);
for (int i = 0; i < _numPricingColumns; i++)
{
DataGridViewColumn column = new DataGridViewTextBoxColumn
{
Name = $"Price {i + 1}",
DataPropertyName = $"Price{i + 1}"
};
GridView.Columns.Add(column);
}
}
}
If I don't use BindingView I can set it up all by hand, but then I have to maintain the rows and columns myself. I'd like to use BindingView but this doesn't seem to support mapping many columns to an array.
I found I could get the pricing columns to be handled by drawing them. The use I needed was readonly so this is my solution for now:
private void OnCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
for (int i = 0; i < _numPricingColumns; i++)
{
var name = $"Price {i + 1}";
var column = GridView.Columns[name];
if (column.Index == e.ColumnIndex && e.RowIndex >= 0)
{
var row = GridView.Rows[e.RowIndex];
var record = row.DataBoundItem as PricingRecord;
if (record != null)
{
var selected = (e.State & DataGridViewElementStates.Selected) != 0;
using (var brush = new SolidBrush(selected ? e.CellStyle.SelectionForeColor : e.CellStyle.ForeColor))
{
e.PaintBackground(e.ClipBounds, selected);
e.Graphics.DrawString(record.Prices[i].ToString("N"), e.CellStyle.Font, brush,
e.CellBounds.X + 2.0f, e.CellBounds.Y + 2.0f, StringFormat.GenericDefault);
e.Handled = true;
}
}
}
}
}
A faster and more flexible solution proved to be dropping BindingList and directly poking the cells in the grid. The need to map an array field to multiple columns becomes moot as it's done by hand.
I have little issue with checkbox added programmatically. I don't know how to check which checkbox are selected, when I hit "Send Button".
layout.RemoveAllViewsInLayout();
CheckBox _Options = new CheckBox(Activity);
ScrollView _Scroll = new ScrollView(Activity);
_Scroll.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
LinearLayout _LScroll = new LinearLayout(Activity);
_LScroll.LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
_LScroll.Orientation = Orientation.Vertical;
_LScroll.SetGravity(GravityFlags.CenterHorizontal);
//_Scroll.AddView(_LScroll);
Button _Send = new Button(Activity);
_Send.Text = "WyĆlij";
_Send.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
for (int i = 0; i < _Item.options.Length; i++)
{
_Options.Text = _Item.options[i];
_Options.Id = i;
_Options.LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
_LScroll.AddView(_Options);
}
_Send.Click += delegate
{
_MultiAnswer._QuestionId = _Item.id;
for(int i = 0; i < _Item.options.Length; i++)
{
if (_Options.Selected == true)
{
_MultiAnswer._AnwserOptionIds.SetValue(i + 1, i);
}
}
output = JsonConvert.SerializeObject(_MultiAnswer);
SendJson(_Url, DataCache._Login, output);
SetLayout(layout, btn);
};
_Scroll.AddView(_LScroll);
layout.AddView(_Scroll);
layout.AddView(_Send);
I'll try to work on ID of checkbox, but I really don't know how to do it. I was thinking on method, which give me code which create checkbox, but still don't know how to check if checkbox is selected.
I understand that you've many checkbox controls. So add them to a list as follows:
List<Checkbox> checkboxes = new List<Checkbox>
{
chk1, chk2, chk3
};
When you want to know which ones are checked, you'll do this:
IEnumerable<Checkbox> checkedCheckboxes = checkboxes.Where(chk => chk.Checked);
This is a quick and dirty sample on how to generate dynamic cheboxes and retreive their state :
public class MainActivity : Activity
{
public class MyItem
{
public string[] options { get; set; }
public int id { get; set; }
}
public class MyMultiAnswer
{
public int _QuestionId { get; set; }
}
private List<CheckBox> _chkList = new List<CheckBox>();
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
var _Item = new MyItem() { options =new string [] { "aaa", "bbb", "ccc" }, id=0 };
var _MultiAnswer = new MyMultiAnswer() { _QuestionId = 0 };
ScrollView _Scroll = new ScrollView(this);
_Scroll.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
LinearLayout _LScroll = new LinearLayout(this);
_LScroll.LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
_LScroll.Orientation = Orientation.Vertical;
_LScroll.SetGravity(GravityFlags.CenterHorizontal);
TextView txView = new TextView(this);
//_Scroll.AddView(_LScroll);
Button _Send = new Button(this);
_Send.Text = "test";
_Send.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
for (int i = 0; i < _Item.options.Length; i++)
{
CheckBox _Options = new CheckBox(this);
_chkList.Add(_Options);
_Options.Text = _Item.options[i];
_Options.Id = i;
_Options.LayoutParameters = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
_LScroll.AddView(_Options);
}
_Send.Click += delegate
{
_MultiAnswer._QuestionId = _Item.id;
string strChkIds = "";
foreach (var chk in _chkList.Where(c => c.Checked))
{
//_MultiAnswer._AnwserOptionIds.SetValue(_Options.Id + 1, _Options.Id);
//do something
strChkIds += " - " + chk.Id;
}
// or
for (int i = 0; i < _Item.options.Length; i++)
{
if (_chkList[i].Checked == true)
{
//_MultiAnswer._AnwserOptionIds.SetValue(i + 1, i);
//do something
}
}
//output = JsonConvert.SerializeObject(_MultiAnswer);
//SendJson(_Url, DataCache._Login, output);
//SetLayout(layout, btn);
txView.Text = "selected ids " + strChkIds;
};
_Scroll.AddView(_LScroll);
_LScroll.AddView(_Send);
_LScroll.AddView(txView);
// Set our view from the "main" layout resource
SetContentView(_Scroll);
}
}
This is a sample about how you can achieve this in a minimum effort.
when i tab to itemFooter , databinding will getdata and load continue
public void getFeed()
{
waittingopen();
if (listRSS != null && listRSS.Count > 0)
{
List<Article> listArticle = getArticle();
if (listArticle.Count > 0)
{
if (loadmor != null && list.Items.Contains(loadmor))
{
list.Items.Remove(loadmor);
}
#region add item
for (int i = 0; i < listArticle.Count; i++)
{
dataDetail dataDetail;
if (i == 0 && dtListBoxx.Count == 0)
dataDetail = new dataDetail { title = listArticle[i].title, feedName = listRSS[indexLoadmor].name, Type = "itemBigContent", isVisileLineLeft = System.Windows.Visibility.Collapsed, isVisileBook = System.Windows.Visibility.Collapsed };
else
dataDetail = new dataDetail { title = listArticle[i].title, feedName = listRSS[indexLoadmor].name, Type = "itemContent", isVisileLineLeft = System.Windows.Visibility.Collapsed, isVisileBook = System.Windows.Visibility.Collapsed };
dtListBoxx.Add(dataDetail);
}
#endregion
if (intLoad == 0)
{
listArticle.Clear();
listArticle = null;
indexLoadmor++;
intLoad++;
getFeed();
}
else
{
intLoad = 0;
dataDetail dataLoadmoreItem = new dataDetail { Type = "itemFooter" };
dtListBoxx.Add(dataLoadmoreItem);
this.list.ItemsSource = dtListBoxx;
}
waittingClose();
}
else
{
getfeed = new Getfeed(listRSS[indexLoadmor].link.ToString(), "", listRSS[indexLoadmor].rid, intLoad);
getfeed.onComplete += new Getfeed.DownloadComplete(getfeed_onComplete);
if (intLoad == 1)
intLoad = 0;
}
}
}
how do i can load more data by using this.list.ItemsSource = dtListBoxx ? I tried but listbox is not updated when dataDetail add item
Please help me !
Use ObservableCollection instead of List. It automatically raises OnCollectionChanged event to notify view that some changes in collection are occurred.