i got an ItemsControl with an Expander in it and in the Expander are a view ProgressBars inclued. My problem is when i am loading the data (which is not my performance problem) and then i update PropertyChanged of my ItemSource my gui freezes for a long time cuz it needs so long to render.
Is there a way i can redner the gui elements async so that my gui doesnt freeze???
I already searched a bit, though im not sure if my search results solve my problem.
So i am asking here, hoping for a nice solution.
They gui does look something like this.. though there are usually more elements
you all can imageine the xaml code behind...
private void RefreshOverview(){
...
foreach (Characteristic c in characteristics)
{
Area a = c.Area;
Characteristic c1 = c;
foreach (Line l in lines.Where(l => l.Product.Id == c1.Product.Id))
{
List<IMeasurementSchedule> measurementSchedules;
// take DefaultMeasurementSchedules if exists
if (c.DefaultMeasurementSchedules == null || c.DefaultMeasurementSchedules.Count == 0)
measurementSchedules = new List<IMeasurementSchedule>(l.LineMeasurementSchedules.ToArray());
else
measurementSchedules = new List<IMeasurementSchedule>(c.DefaultMeasurementSchedules.ToArray());
foreach (IMeasurementSchedule ms in measurementSchedules)
{
MeasureCharacteristic mc;
if (a.PeripheryEnabled)
{
Line l1 = l;
foreach (AreaItem ai in areaitems.Where(x => x.AreaId == a.Id && x.LineId == l1.Id))
{
mc = (from cm in _context.CharacteristicMeasures.Local
where cm.Charge == null &&
cm.Characteristic.Id == c.Id &&
cm.Line.Id == l.Id &&
cm.ShiftIndex.Id == actualShiftIndex.Id &&
cm.AreaItem != null &&
cm.AreaItem.Id == ai.Id &&
cm.MeasureScheduleId == ms.Id
select cm).FirstOrDefault() ??
new MeasureCharacteristic
{
Characteristic = c,
Line = l,
ShiftIndex = actualShiftIndex,
AreaItem = ai
};
mc.MeasureSchedule = ms;
characteristicsMeasures.Add(AddMeasures(mc));
}
}
else
{
mc = (from cm in _context.CharacteristicMeasures.Local
where cm.Charge == null &&
cm.Characteristic.Id == c.Id &&
cm.Line.Id == l.Id &&
cm.ShiftIndex.Id == actualShiftIndex.Id &&
cm.MeasureScheduleId == ms.Id
select cm).FirstOrDefault() ??
new MeasureCharacteristic {Characteristic = c, Line = l, ShiftIndex = actualShiftIndex};
mc.MeasureSchedule = ms;
characteristicsMeasures.Add(AddMeasures(mc));
}
}
}
}
MeasureCharacteristics = characteristicsMeasures;
MeasureCharacteristicsByType =
CharacteristicMeasureGroupedByType.GetExpanderViewProductItems(characteristicsMeasures);
}
thats my code ;) MeasureCharacteristicsByType is a IEnumerable<CharacteristicMeasureGroupedByType> i do bind my itemsource to. if you need more information just ask!!!
UPDATE
here is my link to my xaml code..
http://pastebin.com/UA777LjW
You are mixing logic to build your data and rendering operations.
Isolate the one from the other to identify which is taking time.
For example don't affect MeasureCharacteristicsByType in the same for loop as the linq queries.
Then measure times with a StopWatch instance.
If the rendering takes the most time, insert the items in the MeasureCharacteristicsByType one by one (not at the same time), with this kind of instruction to render them one after the other :
foreach(var charMeasureByType in CharacteristicMeasureGroupedByType.GetExpanderViewProductItems(characteristicsMeasures))
{
Dispatcher.BeginInvoke(new Action<OneTypeHere>((OneTypeHere item) =>
{
MeasureCharacteristicsByType.Add(item)
}), DispatcherPriority.Background, charMeasureByType);
}
Edit : OneTypeHere is the type of charMeasureByType.
Related
Im trying to disable a RadGridView row based on a value in that row?
I have tried the below code in the RowLoaded event but it seems to disable all rows.
var isEnrolled = (from c in masterList
where c.StudentId == StudentID
where c.Rolls[0].RollId == item.RollId.ToString()
select c.IsEnrolled).FirstOrDefault();
if (isEnrolled)
e.Row.IsEnabled = false;
Can it be done in same event, so if a row contains the word "Confirmed" the row is disabled?
foreach(DataGridRow item in RollListGrid.Items)
{
//Disable row if it contains "Confirmed"
}
And one more, how can i check a checkbox in a row if the query returns true?
var isProspectiveStudent = (from c in masterList
where c.StudentId == StudentID
where c.Rolls[0].RollId == item.RollId.ToString()
select c.IsProspectiveStudent).FirstOrDefault();
if (isProspectiveStudent){
//Check the relevant checkbox
}
Thanks!!
I managed to achieve what I wanted to with the below code.
foreach (var x in e.Row.Cells)
{
if (((GridViewCell)x).Value != null && ((GridViewCell)x).Value.ToString() == "Confirmed" && x.Column.UniqueName.IndexOf("5") != -1)
{
e.Row.IsEnabled = false;
break;
}
}
We have a web service that picks up a report from a server and returns it to the Silverlight GUI. In the GUI we have an event handler that calls the following function:
private void PopulateDataGrids()
{
try
{
reportTitle = reportDataUtil.ReportHeader.Rows.First(r => r.Items[ReportTools.FIELDNAME_STRING].ToString() == ReportTools.FIELDVALUE_TITLE).Items[ReportTools.FIELDVALUE_STRING].ToString();
dg_Report_Header.DataSource = reportDataUtil.ReportHeader;
dg_Report_Header.CanUserSortColumns = false;
dg_Report_Header.CanUserReorderColumns = false;
dg_Report_Header.CanUserResizeColumns = true;
dg_Report_Header.DataBind();
dg_Report_Header.UpdateLayout();
dg_Report_Detail.DataSource = reportDataUtil.ReportDetails;
dg_Report_Detail.CanUserSortColumns = true;
dg_Report_Detail.CanUserReorderColumns = true;
dg_Report_Detail.CanUserResizeColumns = true;
dg_Report_Detail.DataBind();
dg_Report_Detail.UpdateLayout();
//Hide the ElementID colmun
if (dg_Report_Detail.Columns.Count > 0)
{
var col = dg_Report_Detail.Columns.FirstOrDefault(dc => dc.Header.ToString() == NetVisSolution.Reports.ReportTools.COLUMNNAME_ELEMENTID);
if (col != null)
{
col.Visibility = System.Windows.Visibility.Collapsed;
}
}
}
catch (Exception)
{
ClearResources();
closeReportDataViewer();
ErrorWindow.CreateNew("Unable to open selected report data, the file maybe corrupted or not \nin the server specified location.");
//throw new Exception(ex.Message, ex.InnerException);
}
}
Trouble is, the detail table can be 14000 rows long, taking up more than a megabyte. When such a report is loaded, the dg_Report_Detail.DataBind(); call takes several minutes and locks up the GUI.
Is there a simple way to do this asynchronously or in such a manner that the application remains responsive?
Thanks in advance,
--- Alistair.
Although DataGrid implements Row Virtualization, it can still spend a lot of time calculating the height of each row separately. Assigning a RowHeight will skip all those calculations.
<sdk:DataGrid AutoGenerateColumns="False" RowHeight="20">
</sdk:DataGrid>
I have a program that displays lines from a log file.
They are parsed and put into a class called LogLine then displayed in a datagrid
Here is my filter function:
ICollectionView view = CollectionViewSource.GetDefaultView(this.LogView.ItemsSource);
bool traceChecked = this.TraceCheckbox.IsChecked.HasValue && this.TraceCheckbox.IsChecked.Value;
bool debugChecked = this.DebugCheckbox.IsChecked.HasValue && this.DebugCheckbox.IsChecked.Value;
bool infoChecked = this.InfoCheckbox.IsChecked.HasValue && this.InfoCheckbox.IsChecked.Value;
bool warnChecked = this.WarnCheckbox.IsChecked.HasValue && this.WarnCheckbox.IsChecked.Value;
bool errorChecked = this.ErrorCheckbox.IsChecked.HasValue && this.ErrorCheckbox.IsChecked.Value;
string filtertext = this.TextFilterBox.Text;
view.Filter = o =>
{
LogLine line = o as LogLine;
return line != null
&& (((traceChecked && line.Trace)
|| (debugChecked && line.Debug)
|| (infoChecked && line.Info)
|| (warnChecked && line.Warn)
|| (errorChecked && line.Error))
&& line.Message.Contains(filtertext));
};
This function is slow, already, taking close to 5 seconds on a log with 200000 lines.
What can be done to speed this up?
I implemented a real ViewModel per HighCore's suggestion. This is marginally faster, but it is still taking 5-6 seconds to go threw all the lines of the ObservableCollection
ICollectionView view = CollectionViewSource.GetDefaultView(this.LogView.ItemsSource);
LogViewModel lvm = (LogViewModel)this.DataContext;
view.Filter = o =>
{
LogLine line = o as LogLine;
if (line == null || !line.Message.Contains(lvm.FilterText))
{
return false;
}
switch (line.LogLevel)
{
case LogViewModel.LogLevel.Trace:
return lvm.Trace;
case LogViewModel.LogLevel.Debug:
return lvm.Debug;
case LogViewModel.LogLevel.Info:
return lvm.Info;
case LogViewModel.LogLevel.Warn:
return lvm.Warn;
case LogViewModel.LogLevel.Error:
return lvm.Error;
default:
return false;
}
};
I wrote a similar log viewer app but used a different approach.
I perform an initial parse into a class like your LogLine and store them in a list. Then as the user chooses various filter combinations, I use Linq to build an IEnumerable of filter matches which is bound to an items control (in my case a ListView). You could use an ObservableCollection and clear / populate with the same results if you prefer.
I just tested with a 31MB file (240k lines) and the results are displayed in under a second when changing the filter.
As you can tell from my code, I'm absolute a beginner. After searching through other similar issues on LINQ to SQL problems, I find myself still seemingly stuck on two objectives. 1) Adding a new entry with input from the user selection from three comboboxes and a datepicker and 2) Updating an existing database entry using interactions from the datagridview.
My windows form datagridview is displaying the following output
**select b.Date, a.EmployeeName,
c.ProjectName, b.Hours
from dbo.Employees a
left outer join dbo.EmployeeProjectHours b
on a.EmployeeId = b.EmployeeId
left outer join dbo.Projects c
on b.ProjectId = c.ProjectId**
Here is my ADD method the user is providing me with ProjectName, EmployeeName, Date and Hours. Any thoughts for a layman would be appreciated.
I don't get an error running the insert, but nothing is added to my dab as well
using (ProjectHoursDataContext dbInsert = new ProjectHoursDataContext())
{
this.Validate();
EmployeeProjectHour empHours = new EmployeeProjectHour();
empHours.Date = dateDateTimePicker.Value;
empHours.Hours = Convert.ToDecimal(hoursComboBox.Text);
empHours.ProjectId = dbInsert.Projects.First(p => p.ProjectName == projectNameComboBox.Text).ProjectId;
empHours.EmployeeId = dbInsert.Employees.First(m => m.EmployeeName == employeeNameComboBox.Text).EmployeeId;
db.EmployeeProjectHours.InsertOnSubmit(empHours);
dbInsert.SubmitChanges();
}
Here is my Update attempting to use updates directly from the datagridview. I get the following error: A first chance exception of type 'System.ArgumentException' occurred in System.Windows.Forms.dll
using (ProjectHoursDataContext dbUpdate = new ProjectHoursDataContext())
{
this.Validate();
dataGridView1.AutoGenerateColumns = true;
projectBindingSource.DataSource = dbUpdate;
projectBindingSource.DataMember = "Updates";
projectBindingSource.EndEdit();
dbUpdate.SubmitChanges();
}
My best guess so far is, you want to edit and change existing Employee, Project and EmployeeProjectHours records.
So you would do:
using (ProjectHoursDataContext dbInsert = new ProjectHoursDataContext())
{
this.Validate();
// Get the records
Employee emp = new Employee();
Project proj = new Project();
EmployeeProjectHour empHours = new EmployeeProjectHour();
// Set new values to Employees tables
emp = dbInsert.Employees
.First(m => m.EmployeeName == employeeNameComboBox.Text);
//just get the empployee
//setting values will update it
emp.EmployeeName = employeeNameComboBox.Text;
// GET an existing project
proj = dbInsert.Projects
.First(p => p.ProjectName == projectNameComboBox.Text);
//update its values.
proj.ProjectName = projectNameComboBox.Text;
proj.ProjectDescription = "Test";
//GET an empHours
empHours = dbInsert.Projects.First(p => p.EmployeeId == emp.EmployeeId &&
p.ProjectId == proj.ProjectId);
//set its values
empHours.Date = dateDateTimePicker.Value;
empHours.Hours = Convert.ToDecimal(hoursComboBox.Text);
dbInsert.SubmitChanges();
}
Aside from the new code below, I also set my increment status for my projects database to NO. I had set it yes from a previous stackoverflow discussion. Thanks
public void AddInfo()
{
db.Connection.Open();
this.Validate();
EmployeeProjectHour empHours = new EmployeeProjectHour();
empHours.Date = dateDateTimePicker.Value;
empHours.Hours = Convert.ToDecimal(hoursComboBox.Text);
empHours.ProjectId = db.Projects.First(p => p.ProjectName == projectNameComboBox.Text).ProjectId;
empHours.EmployeeId = db.Employees.First(m => m.EmployeeName == employeeNameComboBox.Text).EmployeeId;
db.EmployeeProjectHours.InsertOnSubmit(empHours);
db.SubmitChanges();
db.Connection.Close();
}
I will have my data grid view as follows
RecordTypeCode Content
FileHeader 1111111111111
BatchHeader 5666666666666
EntryDetail 656546545644545
BatchControl 8654654564564
FileControl 945645
I would like to have check boxes only at BatchHeader and EntryDetail is it possible. This is the way i am binding data to data grid view
if (line.StartsWith("1"))
{
dcID = new DataColumn("RecordTypeCode");
dt.Columns.Add(dcID);
DataColumn dcSomeText = new DataColumn("Content");
dt.Columns.Add(dcSomeText);
dr = dt.NewRow();
dr["RecordTypeCode"] = filecontrolvariables.rectype[line.Substring(0, 1)].ToString();
dr["Content"] = line;
dt.Rows.Add(dr);
}
if (line.StartsWith("5"))
{
dr = dt.NewRow();
dr = dt.NewRow();
dr["RecordTypeCode"] = filecontrolvariables.rectype[line.Substring(0, 1)].ToString();
dr["Content"] = line;
dt.Rows.Add(dr);
}
I would like to add check boxes as per needed can any one help me
I tried this
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
if (dataGridView2.Rows[e.RowIndex].Cells["RecordTypeCode"].Value.ToString() == "BatchHeader")
{
e.PaintBackground(e.ClipBounds, true);
e.Handled = true;
}
}
Sample image when my data binded
I tried this
int columnIndex = -1;
int rowIndex = -1;
if (dataGridView2.CurrentCell != null)
{
columnIndex = dataGridView2.CurrentCell.ColumnIndex;
rowIndex = dataGridView2.CurrentCell.RowIndex;
}
if (columnIndex == 0)
{
if (e.RowIndex >= 0)
{
if (dataGridView2.Rows[e.RowIndex].Cells["RecordTypeCode"].Value.ToString() == "Batch Header")
{
e.PaintBackground(e.ClipBounds, true);
e.Handled = true;
}
}
}
But my corresponding row is showing empty when i check it only for BatchHeader
You need to use the cellpainting event to not display the checkbox at all. I'm not sure if this would have other consquences during data binding but it did not display the checkbox for the rows that I wanted.
I have updated the method for what you would need.
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
//if (e.ColumnIndex == <index of your checkbox column> && (e.RowIndex == 1 || e.RowIndex == 2))
if (dataGridView2.Rows[e.RowIndex].Cells["RecordTypeCode"].Value.ToString() == "Batch Header" && e.ColumnIndex == <index of your checkbox column should be 0 sicne its the first column>)
{
e.PaintBackground(e.ClipBounds, true);
e.Handled = true;
}
}
}
The condition for e.RowIndex == 1 || e.RowIndex == 2 is based on the fact that batchheader and entrydetail wont change their position. But if that is dynamic, then you can just check the text in the recordtype column to match BatchHeader and EntryDetail.
The if statement is the most important, it checks which particular cell (row, column) is the one you dont want any checkbox in. They must be used with an AND (&&) as you want one particular cell. You can use the code I have written as is if what you have explained is what you need. You will probably need to add one more check in the if statement for entry detail which needs to be done with an OR (||) with the batch header check. Exactly how I have in the commented part of the code, taking notice to the brackets especially.
I saw the solution at this link which worked when I tried it. There are others mentioned incase this isn't suitable for what you want.