Sunday, January 24, 2010

Refresh WPF DataGrid

I am using WPF DataGrid for displaying a list of items. I had to modify an item, but the item had no INotifyPropertyChanged event on that property (it was a collection).

So my first idea was:

  1. Update the list behind ItemsSource
  2. Set ItemsSource property to null to force unbinding
  3. Set ItemsSource property to the new collection
  4. Set the SelectedItem to the new item
  5. Call ScrollIntoView() on the new item

Well, I got a huge exception at step 5. There must be a simpler solution. And there is.

The DataGrid generates a view of the ItemsSource. All I have to do is call the Items.Refresh() method, and it will rebind to the ItemsSource. Everything will be rebound, all updates will be visible. Selected item kept, visibility kept.

Monday, January 18, 2010

DispatcherPriority

I had a very tough problem today. The following code did not work correctly:

var books = _bookRepository.All;
 
Dispatcher.Invoke(
    new ThreadStart(delegate
                        {
                            foreach (Book book in books)
                            {
                                CatalogItems.Add(new BookViewModel(book));
                            }
 
                            OnLoaded(this, EventArgs.Empty);
                            OnPropertyChanged("CatalogItems");
                        }),
    DispatcherPriority.ApplicationIdle);

When I run the code above the first time, the debugger didn’t even break into the dispatched code. The subsequent calls were fine.

Finally I realized that DispatcherPriority.ApplicationIdle should be changed to DispatcherPriority.Normal – and everything was fine. Don’t forget to check the DispatcherPriority value of the dispatcher! It’s hard to debug and hard to recognize.

These are the possible dispatcher priority levels:

Priority

Description

Inactive

Work items are queued but not processed.

SystemIdle

Work items are only dispatched to the UI thread when the system is idle. This is the lowest priority of items that are actually processed.

ApplicationIdle

Work items are only dispatched to the UI thread when the application itself is idle.

ContextIdle

Work items are only dispatched to the UI thread after higher-priority work items are processed.

Background

Work items are dispatched after all layout, rendering, and input items are processed.

Input

Work items are dispatched to the UI thread at the same priority as user input.

Loaded

Work items are dispatched to the UI thread after all layout and rendering are complete.

Render

Work items are dispatched to the UI thread at the same priority as the rendering engine.

DataBind

Work items are dispatched to the UI thread at the same priority as data binding.

Normal

Work items are dispatched to the UI thread with normal priority. This is the priority at which most application work items should be dispatched.

Send

Work items are dispatched to the UI thread with the highest priority.

 

Link: Build More Responsive Apps With The Dispatcher (MSDN)

Monday, January 11, 2010

Events with anonymous delegate

I subscribed to an event with an anonymous delegate. Later I was in need for a solution to be able to unsubscribe this delegate. This is a simple solution for the problem:

public class ClassName
{
    MouseButtonEventHandler eventHandler;
 
    public ClassName()
    {
        eventHandler = delegate
                                        {
                                            // operations
                                        };
    }
 
    void Functionality()
    {
        if (_subscribe)
        {
            _object.MouseLeftButtonDown += eventHandler;
        }
        else
        {
            _object.MouseLeftButtonDown -= eventHandler;
        }
    }
}

Saturday, January 9, 2010

NHibernate and SQLite in-memory database

I’m implementing and in-memory database-based unit test framework for an application. I hope it speeds up unit tests. Unfortunately I have to redesign my entity repositories to support in-memory behavior. As far as I can learn from SUT behavior, SQLite will create a brand new database when
  • you close the session
  • you commit or close a transaction
It means you can’t use using(ISession) and using(ITransaction transaction){ … transaction.Commit() } constructs in the repository.