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.
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;
}
}
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.
Peeps,
Im a born again virgin to Silverlight so please bear with me. I have two seperate DomainServices, pointing to two different SQL Database Servers. Within these Domain Services I have setup some IQueryables in each Domain Service.
I need to merge two IQueryables together from seperate DomainServices. Im sure this has got to be do-able.
Below are the two domain services.
I want to merge GetCustomCallLogs (from HEATLiveDomainService) together with GetTblCallsLogged (from HeatDomainService). The key in GetCustomCallLogs would be the CallID and the key in GetTblCallsLogged would be the RecID.
If its possible to do i understand i would need to create a new type to take into account any fields from the two joined tables.
Hopefully ive explained my scenario, and im not being dumb.
Thanks in advance
public class HEATLIVEDomainService : LinqToEntitiesDomainService<HeatIT9_LiveEntities>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Assignees' query.
public IQueryable<Assignee> GetAssignees()
{
return this.ObjectContext.Assignees;
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'CallLogs' query.
public IQueryable<CallLog> GetCallLogs()
{
// return this.ObjectContext.CallLogs.Where(c => DateTime.Parse(c.ClosedDate).Year == 2012 && c.CallStatus == "Closed" && c.ClosedBy.Length > 0);
return this.ObjectContext.CallLogs.Where(c => c.CallStatus == "Closed" && c.ClosedDate.Substring(0, 4).Equals("2013"));
}
public IQueryable<CallLog> GetCallLogsLastThisYear()
{
return this.ObjectContext.CallLogs.Where(c => c.CallStatus == "Closed" && (c.ClosedDate.Substring(0, 4).Equals("2012") || c.ClosedDate.Substring(0, 4).Equals("2013")));
}
public IQueryable<CustomCallLog> GetCustomCallLogs(string year)
{
var result = from i in this.ObjectContext.CallLogs
join p in this.ObjectContext.Assignees on i.ClosedBy equals p.LoginID
where i.CallStatus == "Closed" && i.ClosedDate.Substring(0, 4) == year
select new CustomCallLog
{
Score =
CallLog = i.CallID,
Name = p.Assignee1,
Yr = year,
Mth = i.ClosedDate.Substring(5, 2),
GroupName = p.GroupName
};
return result;
}
public IQueryable<CustomClosedJobs> GetCustomClosedJobs()
{
var result = from i in this.ObjectContext.CallLogs
where i.CallStatus == "Closed" && i.ClosedDate.Substring(0, 4) =="2012"
group i by i.ClosedDate.Substring(5,2) into y
select new CustomClosedJobs
{
Type = "heat",
ClosedCalls = y.Count(),
Mth =y.Key
};
return result;
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Subsets' query.
public IQueryable<Subset> GetSubsets()
{
return this.ObjectContext.Subsets;
}
}
public class HEATDomainService : LinqToEntitiesDomainService<FEEDBACKPRDEntities1>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'qryStoringLogs' query.
public IQueryable<qryStoringLog> GetQryStoringLogs()
{
return this.ObjectContext.qryStoringLogs.OrderBy(e => e.monthno);
}
public IQueryable<tblStoringLog> GetTop100Logs()
{
return this.ObjectContext.tblStoringLogs.OrderByDescending(e => e.responsetime).Take(100);
}
public IQueryable<tblStoringLog> GetLogCount(DateTime s, DateTime e)
{
return this.ObjectContext.tblStoringLogs.Where(x => x.responsetime >= s && x.responsetime <= e);
}
public IQueryable<qryStoringLog> GetLogs(int year, int mth)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.Month.Equals(mth) && e.yr.Equals(year));
}
public IQueryable<qryStoringLog> GetLogsForYear(int year)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.yr.Equals(year)).OrderBy(e => e.monthno);
}
public DateTime GetFirstDate()
{
return (DateTime)this.ObjectContext.tblStoringLogs.OrderBy(e => e.responsetime).First().responsetime;
}
public DateTime GetLastDate()
{
return (DateTime)this.ObjectContext.tblStoringLogs.OrderByDescending(e => e.responsetime).First().responsetime;
}
public IQueryable<tblCallLogged> GetTblCallLoggeds()
{
return this.ObjectContext.tblCallLoggeds;
}
public IQueryable<tblStoringLog> GetTblStoringLogs()
{
return this.ObjectContext.tblStoringLogs;
}
[Query(IsComposable = false)]
public IQueryable<qryStoringLog> GetTblStoringLogsStatus(int statusid)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.statusid == statusid);
}
public IQueryable<stResponsesLife_Result> LifeTimeResponses()
{
return this.ObjectContext.stResponsesLife().AsQueryable();
}
public IEnumerable<CustomLifetime> GetCustomLifeTime()
{
var result = from i in this.ObjectContext.stResponsesLife().ToList()
select new CustomLifetime
{
Dates = i.Dates,
Vals = (int)i.Vals
};
return result;
}
public int GetAllResponses()
{
return this.ObjectContext.qryStoringLogs.Count();
}
}
Caveats:
Cannot have linked servers, so doing it at the source (SQL Server) is out of the question.
Cannot create a SP and use OpenQuery (well i could but i want to learn to do it correctly), as im sure this isnt the correct way of doing it.
You may need a third type to wrap the two different types returned from each service, but this depends upon how you want to use it.
An ItemsControl wont care about what types are in the collection (Listbox, combobox etc), but GridView type controls might be picky.
Using linq, both lists can simply be merged. Something like the following should do the trick:
collection1.Select(o => (object)o).Concat(collection2.Select(o => (object)o));
The Select and Cast is so that an appropriate generic collection is created by the query.
This can be adjusted to incorporate conversion to your wrapper type too. ie Instead of casting to Object, just return a new instance of your wrapper class instead.
You can even use a Union if appropriate.
Putting it all together:
collection1.Select(o => new MyWrapperType(o))
.Union(collection2.Select(o => new MyWrapperType(o)));
I am trying to implement a Search as you type functionality ( like the one in the search in the default email app ) - I have a listbox with say 50 items - each item bound to a class object which has string fields ... I wish to search and display items which have the text in the search box in one of their string fields - this as the user keys in to the textbox ... tried a couple of approaches -->
1 >> Using a CollectionViewSource
- Bound a CollectionViewSource to All the items from the DB
- Bound the List Box to a CollectionViewSource
- Setting the filter property of the CollectionViewSource - to whose function which searchs for the text in the Search box in the items and set the e.Accepted - on every keyup event
- Filtering works fine but its slow with 50 items :( - guess cos of filter taking each item and checking if to set e.Accepted property to true
.... One DB call on load but seems to be a lot of processing to decide which element to disply in the filer by the CollectionViewSource
2 >> Filter # DB level
- on keyup - sending the text in the search box to the ViewModel where a function returns an ObservableCollection of objects which has the search string
- ObservableCollection is bound to the listbox
.... Not much processing # the top layer but multiple DB calls on each Keypress - still slow but just a tad faster than Approach One
Is there any other approch you would recommend ? or any suggestions to further optimize the above mentioned approaches? - any tweak to give smooth functioning for the search?
First time into mobile dev :) ... Thanx in advance :)
You can optimize the search process further by delaying the search action by x milliseconds to allow the user to continue the writing of the search criteria. This way, each new typed char will delay the search action by xxx milliseconds till the last char where the action is triggered, you'll get a better performance using just one call instead of say 10 calls. Technically speaking, you can achieve this by using a Timer class.
Here you'll find a sample source code example that shows u how to implement this.
private void txtSearchCriteria_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtSearchCriteria.Text == "Search ...")
return;
if (this.deferredAction == null)
{
this.deferredAction = DeferredAction.Create(() => ApplySearchCriteria());
}
// Defer applying search criteria until time has elapsed.
this.deferredAction.Defer(TimeSpan.FromMilliseconds(250));
}
private DeferredAction deferredAction;
private class DeferredAction
{
public static DeferredAction Create(Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
return new DeferredAction(action);
}
private Timer timer;
private DeferredAction(Action action)
{
this.timer = new Timer(new TimerCallback(delegate
{
Deployment.Current.Dispatcher.BeginInvoke(action);
}));
}
public void Defer(TimeSpan delay)
{
// Fire action when time elapses (with no subsequent calls).
this.timer.Change(delay, TimeSpan.FromMilliseconds(-1));
}
}
public void ApplySearchCriteria()
{
ICollectionView dataView = this.ViewSource.View;
string criteria = this.txtSearchCriteria.Text;
string lowerCriteria = criteria.ToLower();
using (dataView.DeferRefresh())
{
Func<object, bool> filter = word =>
{
bool result = word.ToString().ToLower().StartsWith(lowerCriteria);
return result;
};
dataView.Filter = l => { return filter.Invoke(l); };
}
this.lstWords.ItemsSource = dataView;
if (this.lstWords.Items.Count != 0)
{
this.lblError.Visibility = Visibility.Collapsed;
}
else
{
this.lblError.Visibility = Visibility.Visible;
}
}
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.