'ListView' position after refresh - c#

I am populating a ListView with two data sets from SQL. This happens every 15 seconds. How can I keep the scrolled-to position and still refresh the data? I have seen some questions here with related issues but none really address my specific issue. I have tried the TopMost option with limited success.
Any suggestions on how I can keep the scrolled-to position? Here is a bit of code that I use to populate the data for the ListBox.
private void PopulateData()
{
_agent.Stop();
listView1.Items.Clear();
listView1.Groups.Clear();
listView1.BeginUpdate();
string filter;
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt1.Columns.Add("Name", typeof(string));
dt1.Columns.Add("Status", typeof(string));
dt1.Columns.Add("Time", typeof(double));
dt1.Columns.Add("Calls", typeof(double));
dt1.Columns.Add("InProgress", typeof(double));
dt1.Columns.Add("Region", typeof(string));
dt2.Columns.Add("Name", typeof(string));
dt2.Columns.Add("CChats", typeof(double));
dt2.Columns.Add("AChats", typeof(double));
foreach (DataRow dr in _agentStates.Rows)
{
DataRow row = dt1.NewRow();
row["Name"] = dr[0].ToString();
row["Status"] = dr[1].ToString();
row["Time"] = Convert.ToDouble(dr[2].ToString());
row["Calls"] = Convert.ToDouble(dr[3].ToString());
row["InProgress"] = Convert.ToDouble(dr[4].ToString());
row["Region"] = dr[5].ToString();
dt1.Rows.Add(row);
}
foreach (DataRow dr in _chatCount.Rows)
{
DataRow row = dt2.NewRow();
row["Name"] = dr[0].ToString();
row["CChats"] = Convert.ToDouble(dr[1].ToString());
row["AChats"] = Convert.ToDouble(dr[2].ToString());
dt2.Rows.Add(row);
}
var result = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable()
on (string)table1["Name"] equals (string)table2["Name"]
into joinedDt
from table2 in joinedDt.DefaultIfEmpty()
select new
{
Name = (string)table1["Name"],
Status = (string)table1["Status"],
Time = (double)table1["Time"],
Calls = (double)table1["Calls"],
InProgress = (double)table1["InProgress"],
Region = (string)table1["Region"],
CChats = (table2 != null ? (double)table2["CChats"] : 0),
AChats = (table2 != null ? (double)table2["AChats"] : 0)
};
foreach (var item in result)
{
if (item.Status != "NLO" && item.Status !="Webchat Account")
{
var calls = item.Calls + item.CChats;
var lvi = new ListViewItem(item.Name);
lvi.SubItems.Add(item.Status);
lvi.SubItems.Add(Conv.Time(item.Time));
lvi.SubItems.Add(item.Calls.ToString());
lvi.SubItems.Add(item.CChats.ToString());
lvi.SubItems.Add((item.AChats + item.InProgress).ToString());
lvi.SubItems.Add(calls.ToString());
this.listView1.Items.Add(lvi);
}
}
listView1.EndUpdate();
_agent.Start();
}

Use the listview in VirtualMode mode and implement the RetrieveVirtualItem event.
It will give you a better control over what is visible, and you don't need to clear all items to get it updated.
If VirtualMode is set to true, you just set the VirtualListSize to the number of items you want to display in the list. The RetrieveVirtualItem event will be fired for each item the listview wants to show to the user. So if your data changes, you can call the Refresh method of the listview and your RetrieveVirtualItem handler will return the new item data.
Consider this example:
public partial class Form1 : Form
{
private int i = 0;
public Form1()
{
InitializeComponent();
listView1.View = View.Details;
listView1.Columns.Add("Col", 250);
listView1.VirtualMode = true;
listView1.RetrieveVirtualItem += listView1_RetrieveVirtualItem;
listView1.VirtualListSize = 25;
button1.Click += button1_Click;
}
private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
e.Item = new ListViewItem((i + e.ItemIndex).ToString());
}
private void button1_Click(object sender, EventArgs e)
{
// simulate data update
i += 10;
//listView1.VirtualListSize += 5; // you can even change the virtual list size while keeping current scroll position
listView1.Refresh();
}
}

Related

Change FilterEditype of janus griex columns to checklistbox

i Have A Janus Gridex in Windows Form with Several Columns.
I want to Change the FilterEditType of All Columns in This GridEx to Checklistbox. So User Can Filter each Column Based on one or more than one values.
Please Give me the sample Code in C# or VB.net.
You need to add certain events for this one ,
First of all make the GridEx columns FilterEditType = Custom
Then add the Janus.Windows.GridEX.EditControls.CheckedComboBox for each column FilterEditType. For eg: add this events
private void grdTest_InitCustomEdit(object sender, Janus.Windows.GridEX.InitCustomEditEventArgs e)
{
if (e.Column.Key == "ColumnName")
{
cboTest.Visible = true;
e.EditControl = cboTest;
}
}
private void grdTest_EndCustomEdit(object sender, Janus.Windows.GridEX.EndCustomEditEventArgs e)
{
//this (dtTest) datatable is actually the datasource assigned for the grid
dtTest.DefaultView.RowFilter = string.Empty;
cboTest.Visible = false;
string Filter = string.Empty;
if (cboTest.CheckedItems != null)
{
foreach (GridEXRow row in cboTest.DropDownList.GetCheckedRows())
{
if (Filter != string.Empty)
Filter += " OR ColumnName = '";
else Filter = "( ColumnName = '";
Filter += row.Cells[2].Value;
Filter += "'";
}
Filter += " )";
}
dtTest.DefaultView.RowFilter = Filter;
grdTest.DataSource = dtTest.DefaultView;
}
private void grdTest_ClearFilterButtonClick(object sender, Janus.Windows.GridEX.ColumnActionEventArgs e)
{
if (e.Column.Key == "ColumnName")
cboTest.CheckAll();
grdTest_EndCustomEdit(null, null);
}
Then for the checked combo you need to design with multiple columns as you need, but one column should be a CheckBox and make it ActAsSelector = True,
The above example the checked combo has actually 3 columns , first one checkbox , second one is an ID (primary key ) and the last one is the name. I used the name column to filter the datatable.
In the DropDown event of the combo assign the datasource for it from the GirdEx datasource:
private void cboTest_DropDown(object sender, EventArgs e)
{
int C = 1;
DataRow DR;
DataTable dtComboDS= new DataTable();
dtComboDS.Columns.Add("ID", typeof(int));
dtComboDS.Columns.Add("Name", typeof(string));
var depts = (from x in dtTest.AsEnumerable() select x.Field<string>("ColumnName")).ToList();// dtTest is actually the datasource assigned for the GridEx
foreach (var Row in depts.Distinct().ToList())
{
DR = dtComboDS.NewRow();
DR["ID"] = C++;
DR["Name"] = Row;
dtComboDS.Rows.Add(DR);
}
cboTest.DropDownDataSource = dtComboDS;
}
private void cboTest_CloseUp(object sender, EventArgs e)
{
cboTest.Visible = false;
grdTest.UpdateData();
}
On the closeup event hide the checked combo and update the grid to get the result.
Hope this will help !
Good Luck.

Why is nothing displaying in my listbox? C#

My program is supposed to take team names from an XML file and display them in the listbox, and when a team is selected from the listbox, players with a higher batting average on the team are displayed in a datagridview. For some reason nothing is showing up in my listbox, and therefore I cannot select anything and test if my program works.
public partial class Form1 : Form
{
DataSet resultset = new DataSet();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
resultset.ReadXml("Baseball.xml");
var myQuery = resultset.Tables[0].AsEnumerable().Select(row => new
{
teamname = row.Field<string>("Team")
})
.Distinct();
foreach (var rowname in myQuery)
{
listBox1.Items.Add(rowname.teamname.ToString());
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
double TotalhitsAverage, TotalatBatAverage, TeamAverage;
DataTable playerInformation = new DataTable();
DataRow[] tableName = resultset.Tables[0].Select("Team = '" + listBox1.SelectedItem + "'");
playerInformation = tableName.CopyToDataTable();
DataTable clonedcolumns = playerInformation.Clone();
clonedcolumns.Columns[3].DataType = typeof(double);
clonedcolumns.Columns[2].DataType = typeof(double);
foreach (DataRow row in playerInformation.Rows)
{
clonedcolumns.ImportRow(row);
}
TotalhitsAverage = clonedcolumns.AsEnumerable().Average(r => r.Field<double>("hits"));
TotalatBatAverage = clonedcolumns.AsEnumerable().Average(r => r.Field<double>("atBats"));
TeamAverage = TotalhitsAverage / TotalatBatAverage;
DataTable playerAverage = new DataTable();
DataRow rowPlayer = playerAverage.NewRow();
playerAverage.Columns.Add("Player", typeof(String));
playerAverage.Columns.Add("Batting Avg", typeof(double));
for (int i = 0; i < clonedcolumns.Rows.Count; i++)
{
double averageplayer = Convert.ToDouble(clonedcolumns.Rows[i][3]) / Convert.ToDouble(clonedcolumns.Rows[i][2]);
if (TeamAverage <= averageplayer)
{
playerAverage.Rows.Add(clonedcolumns.Rows[i][0].ToString(), Math.Round(averageplayer, 4));
}
}
DataView view = playerAverage.DefaultView;
view.Sort = "Batting Avg DESC";
DataTable sortedDate = view.ToTable();
dgvBaseball.DataSource = sortedDate;
dgvBaseball.AutoSize = true;
}
}

Converting DataSource to DataTable returns null while filtering DataGridView

I'm totally new to Windows Forms and especially DataGridView control.
The problem is when I want to filter DataGridView by a specific column.
In the form load event I bind data to the DataSource of DataGridView like so :
private void Main_Load(object sender, EventArgs e) {
BindingSource bs = new BindingSource();
BindingList<Person> pList = new BindingList<Person> {
new Person {Id = 5, FName = "James", LName = "Allan", Age = 23, Country = "United States"},
// And so on ...
};
bs.DataSource = pList;
dataGridView1.DataSource = bs.DataSource;
}
Then here in click event of button1:
private void button1_Click(object sender, EventArgs e) {
DataTable dt = dataGridView1.DataSource as DataTable;
if (dt != null)
dt.DefaultView.RowFilter = $"FName LIKE '%{textBox1.Text}%'";
}
But the problem is that dt becomes null while dataGridView1.DataSource has value and number of records.
y = x as DataTable;
is not a conversion of your BindingList, but is (usually) equal to
if(x is DataTable)
y = (DataTable)x;
else
y = null;
You have to create a DataTable object by yourself, if you want to use its functionality.
A BindingList cannot be cast to a DataTable.
From How to make a DataTable from DataGridView without any Datasource? you may check this out.
private void button1_Click(object sender, EventArgs e) {
DataTable dt = new DataTable();
foreach(DataGridViewColumn col in dataGridView1.Columns)
{
dt.Columns.Add(col.HeaderText);
}
foreach(DataGridViewRow row in dataGridView1.Rows)
{
DataRow newrow = dt.NewRow();
foreach(DataGridViewCell cell in row.Cells)
{
newrow[cell.ColumnIndex] = cell.Value;
}
dt.Rows.Add(newrow);
}
dt.DefaultView.RowFilter = $"FName LIKE '%{textBox1.Text}%'";
}

Pass gridview data(one page) to another page's gridview control using winforms

I have two pages in my windows application. Both pages have a gridview control. I can pass textbox values into 2nd form but my problem is, I dont know how to pass whole gridview data into 2nd form.
Form1:
public partial class Billing : Form
{
DataTable dt;
public Billing()
{
InitializeComponent();
SetDataTable();
txtBillNo.Text = Convert.ToString(billno);
}
public void btnEnter_Click(object sender, EventArgs e)
{
int row = dgvBilling.RowCount;
DataRow dr;
if (dgvBilling.RowCount != 0)
{
dr = dt.NewRow();
dr["IName"] = txtIName.Text.Trim();
dr["Icode"] = txtIcode.Text.Trim();
dr["Quantity"] = txtQuantity.Text.Trim();
dr["UnitPrice"] = txtUnitPrice.Text.Trim();
int amount = Convert.ToInt32(txtQuantity.Text.Trim()) * Convert.ToInt32(txtUnitPrice.Text.Trim());
dr["amount"] = Convert.ToString(amount);
dt.Rows.Add(dr);
int total = 0;
for (int i = 0; i < dgvBilling.Rows.Count; ++i)
{
total += Convert.ToInt32(dgvBilling.Rows[i].Cells[5].Value);
txtTotal.Text = "Rs/" + "" + Convert.ToString(total);
}
}
else
{
//dt = SetDataTable();
dr = dt.NewRow();
dr["IName"] = txtIName.Text.Trim();
dr["Icode"] = txtIcode.Text.Trim();
dr["Quantity"] = txtQuantity.Text.Trim();
dr["UnitPrice"] = txtUnitPrice.Text.Trim();
int amount = Convert.ToInt32(txtQuantity.Text.Trim()) * Convert.ToInt32(txtUnitPrice.Text.Trim());
dr["Amount"] = Convert.ToString(amount);
dt.Rows.Add(dr);
int total = 0;
for (int i = 0; i < dgvBilling.Rows.Count; ++i)
{
total += Convert.ToInt32(dgvBilling.Rows[i].Cells[5].Value);
txtTotal.Text = "Rs/" + "" + Convert.ToString(total);
}
RetrieveData();
}
}
public DataTable SetDataTable()
{
dt = new DataTable();
DataColumn dc = new DataColumn("IName", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("Icode", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("Quantity", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("UnitPrice", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("Amount", typeof(string));
dt.Columns.Add(dc);
DataGridViewCheckBoxColumn checkBoxColumn = new DataGridViewCheckBoxColumn();
checkBoxColumn.HeaderText = "";
checkBoxColumn.Width = 50;
checkBoxColumn.Name = "checkBoxColumn";
dgvBilling.Columns.Insert(0, checkBoxColumn);
dgvBilling.DataSource = dt;
return dt;
}
private void btnPrintBill_Click(object sender, EventArgs e)
{
PrintBill pb = new PrintBill();
pb.Controls["lblNetAmount"].Text = txtTotal.Text;
pb.Show();
}
}
}
form2:
public partial class PrintBill : Form
{
public PrintBill()
{
InitializeComponent();
Billing bg = new Billing();
dataGridView1.DataSource = bg.RetrieveData();
}
}
When I click PrintBill button I want to show 2nd form with the gridview values of first form...
As a good option you can use a DataTable as data source of your DataGridView and when you need to pass data to other form, use Copy method of that DataTable. Here is an example:
Your GridForm:
public partial class GridForm : Form
{
public GridForm()
{
InitializeComponent();
}
//we will this as data source
private DataTable table;
private void GridForm_Load(object sender, EventArgs e)
{
//Create the data table here and bind it to grid
table = new DataTable();
table.Columns.Add(new DataColumn("IName", typeof(string)));
table.Columns.Add(new DataColumn("Icode", typeof(string)));
table.Columns.Add(new DataColumn("Quantity", typeof(string)));
table.Columns.Add(new DataColumn("UnitPrice", typeof(string)));
table.Columns.Add(new DataColumn("Amount", typeof(string)));
this.dataGridView1.DataSource = table;
}
private void passDataButton_Click(object sender, EventArgs e)
{
//When you need to pass data, use Copy method of data table
var clone = table.Copy();
//Pass data to other form
var f = new OtherForm(clone);
f.ShowDialog();
}
}
Your OtherForm:
public partial class OtherForm : Form
{
DataTable table;
public OtherForm(DataTable value)
{
InitializeComponent();
//get passed data and put it in some member variable for next usages
table = value;
//Bind data to other grid or do other things here or in Form Load event
this.dataGridView1.DataSource = table;
}
}
Actually, you can make that datarow/DataTable a global variable to make it accessible to other class. And also, you can create a public method that returns a datatable like :
public DataTable RetrieveData()
{
DataTable dt;
//retrive necessary data here
return dt;
}

How to add a row into datatable on button click event?

In Windows Forms, I want to add row by row into DataGridView on button click event by taking the values from other controls. I am using DataTable in this case and it is bound to DataGridView.
I am using the following code and it is working fine when the data is inserted for the first time. But my problem is when I click the button for the second time, the first row is overwritten with the second row of data.
private void btnAddToGrid_Click(object sender, EventArgs e)
{
LoadDataGridView();
}
private void LoadDataGridView()
{
dgvAdjustment.DataSource = GetAdjustmentTable();
}
private DataTable GetAdjustmentTable()
{
DataTable adjustmentTable = new DataTable();
DataColumn dataColumn;
dataColumn = new DataColumn("SourceOutletID", typeof(int));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("DestinationOutletID", typeof(int));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("TransactionDate", typeof(DateTime));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("MaterialName", typeof(string));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("AdjustmentType", typeof(int));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("CurrentBalance", typeof(decimal));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("AdjustmentQty", typeof(decimal));
adjustmentTable.Columns.Add(dataColumn);
dataColumn = new DataColumn("NewBalance", typeof(decimal));
adjustmentTable.Columns.Add(dataColumn);
DataRow dataRow = adjustmentTable.NewRow();
dataRow[0] = cmbSourceOutlet.SelectedValue;
dataRow[1] = cmbDestinationOutlet.SelectedValue;
dataRow[2] = TransDateTimePicker.Value;
dataRow[3] = cmbMaterialName.SelectedValue;
dataRow[4] = cmbAdjustmentType.SelectedValue;
dataRow[5] = Convert.ToDecimal(lblCurBalVal.Text);
dataRow[6] = Convert.ToDecimal(lblAdjVal.Text);
dataRow[7] = Convert.ToDecimal(lblNewQtyVal.Text);
int insertPosition = adjustmentTable.Rows.Count;
adjustmentTable.Rows.InsertAt(dataRow, insertPosition);
return adjustmentTable;
}
In ASP .NET applications, I use the session state to check whether DataTable is null by using the following code:
protected void Button1_Click(object sender, EventArgs e)
{
try
{
//Check if previous session is exist
if (Session["MyTable"] == null)
{
dtMyTable = new DataTable("MyTable");
dtMyTable.Columns.Add("Id", typeof(int));
dtMyTable.Columns.Add("LName", typeof(string));
}
else
{
//If yes then get it from current session
dtMyTable = (DataTable)Session["MyTable"];
}
//Add new row every time
DataRow dt_row;
dt_row = dtMyTable.NewRow();
dt_row["Id"] = TextBox1.Text;
dt_row["LName"] = TextBox2.Text;
dtMyTable.Rows.Add(dt_row);
//Update session table
Session["MyTable"] = dtMyTable;
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
What can I do and how can I make the changes to get the right solution in Windows Forms? Any help will be much appreciated!
In GetAdjustmentTable, you are recreating adjustmentTable every time. So a new row will just overwrite the existing one.
You need to modify the code such that adjustmentTable is only created just once and subsequent calls add rows to it. One way to do that would be to make it a private field and to check if it's null, and create it if it is:
private DataTable _adjustmentTable;
private DataTable GetAdjustmentTable()
{
if (adjustmentTable == null)
{
adjustmentTable = new DataTable();
}
....

Categories