How to time ListBox load time WPF - wpf

I'm playing around with DataVirtualization and Async. What are some options I have for quantifying load times of a ListBox that I'm binding my virtualized data collections to?
I need a way to compare the virtualized vs non-virtualized data loading. Have been unsuccessful in locating any resources for this topic.
Should I just put a stopwatch on the ListBox_Loaded event in the code behind?
Thanks in advance!

You can use a System.Diagnostics.Stopwatch for this. Make sure that you start it before you set the ListBox.ItemsSource property and stop it as you said, in the ListBox.Loaded event:
In XAML:
<ListBox Name="ListBox" />
In code constructor:
public MainWindow()
{
InitializeComponent();
ListBox.Loaded += new RoutedEventHandler(ListBox_Loaded);
Items.AddRange(Enumerable.Range(1, 100000000));
stopwatch = new Stopwatch();
stopwatch.Start();
ListBox.ItemsSource = Items;
}
Add the handler with a break point after the call to stop the Stopwatch:
private void ListBox_Loaded(object sender, RoutedEventArgs e)
{
stopwatch.Stop();
TimeSpan elapsedTime = stopwatch.Elapsed;
}
However, unless you have millions of rows of data, or extremely complicated DataTemplates, you may not see much differences. In this simple example, these 100,000,000 numbers are processed in well under one second. Even when I added a larger DataTemplate for the integers, it still rendered them all in just over one second. Furthermore, repeatedly running this scenario will return differing results, so this is somewhat unreliable as well.

Related

How to change cursor while sorting DataGrid?

When DataGrid (wpf) have many rows sorting can take quite long time (up to 5-10 seconds). How to change cursor to Cursors.Wait while searching?
I need somthing like this:
Xaml:
<DataGrid Name="List" SortStart="List_sortStart" SortComplete="sortComplete" />
Xaml.cs
void List_sortStart(object sender, EventArgs e) {
this.Cursor = Cursors.Wait;
}
void List_sortComplete(object sender, EventArgs e) {
this.Cursor = Cursors.Arrow;
}
But DataGrid does not have SortStart and SortComplete events.
The problem is with the WPF/rendering architecture lacking determinacy when processing user interface updates; in this case, a DataGrid sort change. The DataGrid sort operation is begun with a mouse click on the column, which then updates the CollectionView, which finally is rendered visible in the DataGrid at a point later in time. To implement a mouse cursor change as you wish, you need to change the cursor to your busy cursor at the start of the sort operation, and then defer the change back to the normal cursor to a point in time when the user interface context is finished with its final layout work. LUCKILY THIS IS POSSIBLE!
First, one needs a reference to the main rendering thread's dispatcher. A simple way to get it is to create a class-level data item (in the code-behind .CS file) which is initialized by the main user interface thread:
private static readonly Dispatcher UIDispatcher = Dispatcher.CurrentDispatcher;
Next, (in XAML) reference a code-behind handler for the DataGrid's Sorting event, which is executed whenever a sorting operation begins:
<DataGrid ... Sorting="DataGrid_Sorting">
The handler in the code-behind file looks like this:
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
Mouse.OverrideCursor = Cursors.Wait;
UIDispatcher.BeginInvoke((System.Action) (() => { Mouse.OverrideCursor = null; }),
DispatcherPriority.ContextIdle);
}
Note several things in the above code. First, when the sorting operation begins, we override the mouse cursor with the wait animation cursor on the first line. Next, we schedule code to execute on the user interface dispatcher with the DispatcherPriority.ContextIdle priority. This is the secret sauce that defers the code to change the mouse cursor back to normal.
The code to change the mouse cursor back to normal:
Mouse.OverrideCursor = null;
is only executed after the user interface dispatcher is finished with all of the processing of the sorting change/layout update logic and then becomes "idle".
There it is. This "trick" can be useful in many cases when coding for WPF. Put it in your quiver.
DataGrid has Sorting event which occur when the sorting is about to begin. You can attach List_sortStart method to this event.
But then the problem come, as far as I can find, DataGrid doesn't have event that occur when sorting completed. One possible way to workaround this limitation is by creating custom DataGrid with a kind of sorting completed event, see the example in this other SO post :
<local:DataGridExt Name="List" Sorting="List_sortStart" Sorted="List_sortComplete" />

Control Initialization Order Fiasco

Consider the following code:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Slider ValueChanged="slider_ValueChanged/>
<TextBox x:Name="counter"/>
</StackPanel>
</Window>
and
namespace Project1
{
public partial class Window1 : Window
{
public MainWindow() { InitializeComponent(); }
void slider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
counter.Text = e.NewValue.ToString();
}
}
}
Slider will raise its ValueChanged event during initialization while counter is still null.
This is an example of a larger problem that I've been running into using WPF, that UI events can fire at any time, and that there is no single place where I can put my initialization code so that it's guaranteed to run after all the pointers owned by the WPF system have been initialized but before any UI events have fired.
What is the most elegant way to deal with this? The fact that this specific example should use data binding is beside the point.
There are many ways to deal with this, depending on your situation
First off, you could simply recognize the fact that the object might not be initialized and check for that before processing. For example,
if (counter.Text != null)
counter.Text = e.NewValue.ToString();
Second, you could attach your events in the Loaded event of the object so they don't fire until after the object has been initialized.
void Counter_Loaded(object sender, EventArgs e)
{
slider.ValueChanged += Slider_ValueChanged;
}
void Counter_Unloaded(object sender, EventArgs e)
{
slider.ValueChanged -= Slider_ValueChanged;
}
And last of all, you can use WPF's Dispatcher to run events on the UI thread at a different DispatcherPriority. The default is Normal, which runs after Loaded, Render, and DataBind operations
Dispatcher.BeginInvoke(DispatcherPriority.DataBind,
new Action(delegate() { counter.Text = e.NewValue.ToString(); }));
The true answer to this question is to use the MVVM pattern where window code behind files contain little to no initialization code.
In this pattern, the UI is connected to the rest of the code with data binding only. You write special view-model classes that implement INotifyPropertyChanged and take your business logic and expose it as a series of properties that UI binds to.
Naturally, you fully control how your view-models initialize.

Is it ok to use ReportProgress of a BackgroundWorker to do other stuff?

I'm writing a WPF app using an MVVM approach. In my ViewModel, I have an ObservableCollection. Periodically, my app needs to check for new messages, and, if there are any, it needs to add them to the ObservableCollection.
If I try to add to the ObservableCollection in the DoWork, it doesn't work because of thread synchronization issues. It looks like the easiest way to get this to happen on the UI thread is to do a ReportProgress() and update the collection from there.
My question is: Philosophically and technically, is it ok to update the UI from the ReportProgress handler, even though "by the letter of the law" I'm not actually reporting progress.
Is there a more sound way to do this?
* EDIT: Code works using Dispatcher Timer *
ViewModel
class MyViewModel
{
public ObservableCollection<string> MyList { get; set; }
public MyViewModel()
{
MyList = new ObservableCollection<string>();
}
}
"teh codez" - just a sample, not my actual application code.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyViewModel mvm = new MyViewModel();
this.DataContext = mvm;
DispatcherTimer mytimer = new DispatcherTimer();
mytimer.Interval = TimeSpan.FromSeconds(5.0);
mytimer.Tick += new EventHandler(mytimer_Tick);
mytimer.Start();
}
void mytimer_Tick(object sender, EventArgs e)
{
((DispatcherTimer)sender).Stop();
MyViewModel mvm = this.DataContext as MyViewModel;
mvm.MyList.Insert(0, DateTime.Now.ToLongTimeString());
((DispatcherTimer)sender).Start();
}
This looks like it will work well for what I need, and doesn't give me additional baggage that I'm not going to use (e.g. cancel, workercompleted, etc.).
If you're implementing polling-type functionality in your app, it probably makes more sense to use a DispatcherTimer that fires at an interval instead of constantly looping inside of the BackgroundWorker.
http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer.aspx
Sure. That's what the UserState of the EventArgs is designed for.
The reason for the BackgroundWorker is to simplify multithreading. Otherwise, you'd have to do something like Invoke (or BeginInvoke) to handle the same thing the BackgroundWorker is being used for.
I wouldn't do it
It "feels" like something that will cause problems in the future (maybe when someone else tries to add features years from now, maybe when this code is upgraded or ported to an environment with slightly different ReportProgress implementation).
I would just use Dispatcher.BeginInvoke (I also try to avoid using Invoke because it makes one thread wait for the other and reduce the efficiency of using multi-threading in the first place).
But, there are places where just using ReportProgress is the right choice, you need to decide for yourself what is the best thing for your specific situation (the thing I hate most is valuing "best practices" or "architecture" more then producing actual working software)

Silverlight 4 - Print Items Control

I am building a Silverlight 4 application. This application is going to print the contents of an ItemsControl. This ItemsControl uses an ItemTemplate to render the items bound to the control. In all, I have 500 items that are bound to the control.
Oddly, when I attempt to print the ItemsControl, it seems to cut off after a certain point. I cannot tell when it gets cut off. I just know that it gets cut off. I have a hunch it has something to do with virtualization. However, I'm not sure how to overcome this. Currently, I'm printing the ItemsControl like such:
private void printHyperlink_Click(object sender, RoutedEventArgs e)
{
PrintDocument printDocument = new PrintDocument();
printDocument.BeginPrint +=
new EventHandler<BeginPrintEventArgs>(printDocument_BeginPrint);
printDocument.PrintPage +=
new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
printDocument.EndPrint +=
new EventHandler<EndPrintEventArgs>(printDocument_EndPrint);
printDocument.Print("My Items");
}
void printDocument_BeginPrint(object sender, BeginPrintEventArgs e)
{}
void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{ e.PageVisual = myItemsControl; }
void printDocument_EndPrint(object sender, EndPrintEventArgs e)
{}
What am I doing wrong? How do I ensure that all of the items in my ItemsControl are printed as they are rendered?
The printing APIs don't automatically paginate items in an ItemsControl for you. Furthermore, if you are printing something that is already in the visual tree, the result may get clipped to match what is being rendered in the window at the time of printing.
To print multiple pages, you'll need to:
Measure to figure out how many items to show on the page
Create visuals that only show the items you want on that page
Pass them into your "e.PageVisual"
Set e.HasMorePages to be true until you're on the last page
All in all, this can be a fair amount of work. If you're just trying to print an ItemsControl with an ItemTemplate, you'll have to do all of the work above. For slightly more sophisticated scenarios (e.g. adding page numbers, headers/footers, etc.), there's even more work to do.
That said, it's possible to build a library over the simple Silverlight printing APIs that does something like this. I recently blogged a control meant to address exactly this scenario (as well as some of the more sophisticated ones).
http://www.davidpoll.com/2010/04/16/making-printing-easier-in-silverlight-4/

How to databind Multiple Series to a Silverilght Toolkit Chart

I am trying to use databinding to bind data to a Silverlight toolkit chart.
I will have one to many sets of series so cannot determine how many series i need before hand.
I also want to stick to a databinding model and not resort to programmatically adding these series as many other controls bind to this datasource.
I found an article on the web by Jeremiah Morrill that showed a solution for this very problem.
Jeremiah's solution
Now this worked perfectly at first, until I tried to update my databinding's datasource values while the application was running, and this would not reflect. As if it was not subscribed to the PropertyChanged event.
I even bound the same data to a datagrid next to the chart, and the datagrid reacts as expected changing everytime my databinding's datasource values change.
In my ChartHelper from Jeremiah's solution, i have the following dependency property
public static readonly DependencyProperty SeriesSourceProperty =
DependencyProperty.RegisterAttached("SeriesSource",
typeof(IEnumerable),
typeof(ChartHelper),
new PropertyMetadata(SeriesSourceChanged));
The SeriesSourceChanged event is called when my application starts up.
However, when my DataBinding's datasource values change, this is not called again.
So questions are as follows:
How can I capture the PropertyChanged notification with this solution?
Is there something I can add to the DependencyProperty above to capture this?
Is it something i need to add to the chart or series to achieve this?
I have been racking my brain over this for several days, so any help or suggestions will be much appreciated
Thanks!
The SeriesSource type should be ObservableCollection instead of IEnumerable. Then you do something like this:
private static void SeriesSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var sender = o as YourType;
var newCollection = e.NewValue as ObservableCollection<DataSetViewModel>;
if (newCollection != null)
{
newCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(sender.OnCollectionChanged);
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
}
I never did find a solution to this problem and ended up using a chart control from visifire
I found this much easier to customise but never found a neat way of using databinding to achieve this and ended up with a more programattic approach.

Resources