Notes from Daily Encounters with Technology RSS 2.0
 
# Monday, July 21, 2014

Navigation in Windows Store apps is strongly based on the browser model, i.e. the application is keeping a back stack of previously shown pages which will be traversed again when navigating back. For most applications this approach works well, at least most of the time.

But there are some cases in which you don’t want the user to navigate back to a specific page in the history. A typical scenario would be a starting page for creating a new instance of something, e.g. a new game session: a user would navigate to it from the main menu, set some starting parameters there and then continue to the actual game session page. When navigating back, we don’t want the user to see the intermediate session setup page, but to to return directly to the main menu instead.

Desired navigation behavior

Unfortunately there’s no cross-platform way to achieve the desired behavior, therefore there’s also no such built-in functionality available in MvvmCross. Still, the navigation model in MvvmCross is very straight-forward and extensible, making it really simple to add such functionality, if you approach it the right way.

The key to navigation in MvvmCross are ViewPresenters. They handle two main types of messages emitted by view models: ViewModelRequests and PresentationHints. The former are used for switching between views and not applicable to our case; the latter are used for everything else related to navigation and are the ones that we will be taking advantage of.

The basic plan is as follows:

  • Define a new PresentationHint for removing the current (top) view from the navigation back stack
  • Extend the built-in platform-specific ViewPresenter to intercept this navigation hint, modify the back stack accordingly, and delegate all other navigation events to its base class.
  • Use this new ViewPresenter in our application instead of the built-in one.
  • Send the PresentationHint from the view model, we want to see removed from the back stack.

The complete process for a very similar scenario is thoroughly described in Ed Snider’s blog post. I strongly encourage you to read it, as it provides some additional insight into the inner workings of MvvmCross navigation, which will prove useful when you find yourself customizing it for your needs.

As already mentioned, we’ll start out with creating a new PresentationHint class:

public class RemoveTopViewFromBackStackHint
  : MvxPresentationHint
{ }

Our custom ViewPresenter will need to handle this new PresentationHint, as it will be completely ignored by the built-in ViewPresenter:

public class ExtendedViewPresenter : MvxStoreViewPresenter
{
  private readonly Frame _rootFrame;

  public ExtendedViewPresenter(Frame rootFrame) 
    : base(rootFrame)
  {
    _rootFrame = rootFrame;
  }

  public override void ChangePresentation(MvxPresentationHint hint)
  {
    if (hint is RemoveTopViewFromBackStackHint)
    {
      if (_rootFrame.BackStackDepth > 0)
      {
        _rootFrame.BackStack.RemoveAt(_rootFrame.BackStack.Count - 1);
      }
    }

    base.ChangePresentation(hint);
  }
}

For this new ViewPresenter to actually be used, we need to register it instead of the built-in one in our application’s setup class:

public class Setup : MvxStoreSetup
{
  protected override IMvxStoreViewPresenter CreateViewPresenter(Frame rootFrame)
  {
    var presenter = new ExtendedViewPresenter(rootFrame);
    Mvx.RegisterSingleton(presenter);
    return presenter;
  }
  
  // other setup code...
}

Now, everything is ready for sending our new PresentationHint from the view model. Because our code acts on the back stack, we need to wait until the page we want to remove is already in the back stack, therefore we first need to navigate to the next page, and only then send the new navigation hint:

private void OnStartSession()
{
  // code for initializing the session...
  
  ShowViewModel<SessionViewModel>();
  ChangePresentation(new RemoveTopViewFromBackStackHint());
}

When navigating back from SessionView, the intermediate view with the above ChangePresentation call will be skipped, and the previous page from the navigation back stack will be shown instead.

In a previous blog post I described how to unit test navigation between view models in MvvmCross. I used the following MockDispatcher class for logging navigation events and then asserting them:

public class MockDispatcher : MvxMainThreadDispatcher, IMvxViewDispatcher
{
  public readonly List<MvxViewModelRequest> Requests = new List<MvxViewModelRequest>();
  public readonly List<MvxPresentationHint> Hints = new List<MvxPresentationHint>();
 
  public bool RequestMainThreadAction(Action action)
  {
    action();
    return true;
  }
 
  public bool ShowViewModel(MvxViewModelRequest request)
  {
    Requests.Add(request);
    return true;
  }
 
  public bool ChangePresentation(MvxPresentationHint hint)
  {
    Hints.Add(hint);
    return true;
  }
}

This class doesn’t store all the required information to properly test our new type of navigation with page removal from back stack: because ViewModelRequests are stored separately from PresentationHints, there is no way to check whether the order of the two calls was correct. To make that possible the MockDispatcher class needs to be changed, so that both types of events will be stored in a single collection and the order will therefore be preserved:

public class MockDispatcher : MvxMainThreadDispatcher, IMvxViewDispatcher
{
  public class NavigationEvent
  {
    public MvxPresentationHint PresentationHint { get; private set; }
    public MvxViewModelRequest ViewModelRequest { get; private set; }

    public NavigationEvent(MvxPresentationHint presentationHint)
    {
      PresentationHint = presentationHint;
    }

    public NavigationEvent(MvxViewModelRequest viewModelRequest)
    {
      ViewModelRequest = viewModelRequest;
    }
  }

  public readonly List<NavigationEvent> NavigationEvents = new List<NavigationEvent>();

  public bool RequestMainThreadAction(Action action)
  {
    action();
    return true;
  }

  public bool ShowViewModel(MvxViewModelRequest request)
  {
    NavigationEvents.Add(new NavigationEvent(request));
    return true;
  }

  public bool ChangePresentation(MvxPresentationHint hint)
  {
    NavigationEvents.Add(new NavigationEvent(hint));
    return true;
  }
}

The refactoring only slightly changes the assertions for standard back and forward navigation (with and without parameters). At the same time it makes it very simple to assert for our new navigation type as well:

[TestMethod]
public void NavigationWithRemovalFromBackStackTest()
{
  var viewModel = new SetupSessionViewModel();
  viewModel.StartCommand.Execute(null);

  Assert.AreEqual(2, MockDispatcher.NavigationEvents.Count);
  Assert.AreEqual(typeof(SessionViewModel), 
                  MockDispatcher.NavigationEvents[0].ViewModelRequest.ViewModelType);
  Assert.AreEqual(typeof(RemoveTopViewFromBackStackHint), 
                  MockDispatcher.NavigationEvents[1].PresentationHint.GetType());
}

If the navigation type described in this blog post is not exactly what you are looking for, don’t get discouraged. It shouldn’t be difficult to use the same approach to achieve the behavior you require.

Monday, July 21, 2014 6:34:03 AM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Metro | MvvmCross | Testing | Windows Store
# Monday, July 14, 2014

In my spare time I’m developing an application in MvvmCross, using SQLite for local data storage. I’m taking advantage of MvvmCross SQLite-Net plugin. Recently I stumbled across a very strange behavior. The issue involved a fairly simple table with a DATETIME column:

CREATE TABLE [Session] (
  [Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
  [StartedAt] DATETIME NOT NULL, 
  [ClosedAt] DATETIME, 
  [Remark] NVARCHAR(100));

I had a corresponding model class in my code:

public class Session
{
  [PrimaryKey, AutoIncrement]
  public int Id { get; set; }
  public DateTime StartedAt { get; set; }
  public DateTime? ClosedAt { get; set; }
  public string Remark { get; set; }
}

I used the following code for inserting new records:

var session = new Session
{
  StartedAt = DateTime.Now
};
connection.Insert(session);

Re-reading the value from the database also behaved as expected:

var result = connection.Table<Session>.ToList()
                       .Single(s => s.Id == session.Id);
// no error here
Assert.AreEqual(session.StartedAt, result.StartedAt);

Everything seemed okay, until I tried to take a look at the table using SQLite Expert. This is how the above inserted record looked like:

Inserted record, as seen in SQLite Expert

Of course, this called for further investigation.

It turns out, SQLite’s handling of DateTime values is quite strange. There is no separate storage class for DateTime values. Instead, they can be stored as TEXT, REAL or INTEGER values. Built-in date and time functions transparently support either one of those.

To make matters even more complicated, SQLite supports DATETIME data type inside CREATE TABLE statements. Such a column is assigned a NUMERIC type affinity which isn’t a storage class, either. It can contain values of any supported storage class, but tries to convert the inserted text to INTEGER or REAL if it can be done in a lossless manner.

Now is the time to include SQLite-Net into the equation. This library supports storing of DateTime values either as TEXT or as INTEGER values. The mode is selected by the storeDateTimeAsTicks flag when creating a new SQLiteConnection. When creating a table with the library, the column data type is either DATETIME (for TEXT values) or BIGINT (for INTEGER values, i.e. ticks).

By default the library doesn’t store DateTime values as ticks, which should still make everything work fine in my case. But here’s, where the third player enters the stage: MvvmCross SQLite-Net plugin. It is actually a fork of SQLite-Net library with only minor changes to make it work easily with MvvmCross. But the one thing it does change, is the default storage mode for DateTime values: when using the plugin, by default they are stored as ticks, i.e. INTEGER values. This finally explains the strange behavior I observed: obviously SQLite Expert incorrectly interpreted the stored value since it didn’t match its expectations based on the column data type.

I decided to avoid the issue by switching the DateTime storage mode in SQLite-Net back to TEXT. MvvmCross abstracts platform specifics by providing a different SQliteConnectionFactory for each one of them. These factories implement two interfaces: ISQLiteConnectionFactory and ISQLiteConnectionFactoryEx. Platform-specific application setup registers the correct factory which implements both factory interfaces.

Usually you’ll obtain the correct factory in your view model by adding a constructor parameter of the required type. As long as you’re satisfied with the default connection settings, you can use the ISQLiteConnectionFactory interface:

public abstract class ViewModelBase
{
  private readonly ISQLiteConnectionFactory _sqliteConnectionFactory;

  private string _filename = "db.sqlite";

  protected ViewModelBase(ISQLiteConnectionFactory sqliteConnectionFactory)
  {
    _sqliteConnectionFactory = sqliteConnectionFactory;
  }

  protected ISQLiteConnection CreateConnection()
  {
    return _sqliteConnectionFactory.Create(_filename);
  }
}

To change the default setting, ISQLiteConnectionFactoryEx interface needs to be used:

public abstract class ViewModelBase
{
  private readonly ISQLiteConnectionFactoryEx _sqliteConnectionFactory;

  private string _filename = "db.sqlite";

  protected ViewModelBase(ISQLiteConnectionFactoryEx sqliteConnectionFactory)
  {
    _sqliteConnectionFactory = sqliteConnectionFactory;
  }

  protected ISQLiteConnection CreateConnection()
  {
    return _sqliteConnectionFactory.CreateEx(_filename, 
      new SQLiteConnectionOptions { StoreDateTimeAsTicks = false });
  }
}

No other code needs to be changed.

I chose TEXT storage class over INTEGER because of convenience. Having the column data type of DATETIME instead of BIGINT makes it much easier to work with data outside my application. This choice does have a disadvantage, though: less precision in stored values. In particular, the following test will now most likely fail:

var session = new Session
{
  StartedAt = DateTime.Now
};
connection.Insert(session);

var result = connection.Table<Session>.ToList()
                       .Single(s => s.Id == session.Id);
// will fail most of the time:
// milliseconds are stripped when stored to database
Assert.AreEqual(session.StartedAt, result.StartedAt);

In my case this wasn’t an issue. Seconds are enough precise for me. You’ll have to decide for yourself, which mode of storage is more suitable in your situation, though.

Monday, July 14, 2014 6:37:38 AM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | MvvmCross | Sqlite
# Monday, July 7, 2014

IDataErrorInfo interface is really handy when implementing data validation in WPF. There’s great built in support in XAML for displaying validation information to the user when DataContext implements IDataErrorInfo - only ValidatesOnDataErrors property needs to be set to True on the Binding:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <TextBlock Text="Name" Grid.Row="0" Grid.Column="0" />
  <TextBox Text="{Binding Name, ValidatesOnDataErrors=True}"
           Grid.Row="0" Grid.Column="1" />
  <TextBlock Text="Surname" Grid.Row="1" Grid.Column="0" />
  <TextBox Text="{Binding Surname, ValidatesOnDataErrors=True}"
           Grid.Row="1" Grid.Column="1" />
  <TextBlock Text="Phone number" Grid.Row="2" Grid.Column="0" />
  <TextBox Text="{Binding PhoneNumber, ValidatesOnDataErrors=True}"
           Grid.Row="2" Grid.Column="1" />
</Grid>

By default, controls with validation errors are rendered with red border, but they don’t show the actual error message. This can be changed with a custom style applied to them:

<Style TargetType="TextBox">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="Background" Value="Pink"/>
      <Setter Property="Foreground" Value="Black"/>
      <Setter Property="ToolTip" 
              Value="{Binding RelativeSource={RelativeSource Self}, 
                              Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
  <Setter Property="Validation.ErrorTemplate">
    <Setter.Value>
      <ControlTemplate>
        <Border BorderBrush="Red" BorderThickness="1">
          <AdornedElementPlaceholder />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Of course there are many different ways to implement IDataErrorInfo for a DataContext. But since I’ve recently become quite fond of FluentValidation library for implementing validators, I’m going to focus on using it for the rest of this post. Creating a basic validator in FluentValidation usually takes only a couple of lines of code:

public ContactValidator()
{
  RuleFor(login => login.Name).NotEmpty();
  RuleFor(login => login.Surname).NotEmpty();
  RuleFor(login => login.PhoneNumber).NotEmpty();
  RuleFor(login => login.PhoneNumber).Length(9,30);
  RuleFor(login => login.PhoneNumber).Must(phoneNumber => phoneNumber == null || 
                                                          phoneNumber.All(Char.IsDigit))
                                     .WithMessage("'Phone number' must only contain digits.");
}

The easiest way of using it from IDataErrorInfo, would be calling Validate from the indexer and filtering the results by the requested property:

public string this[string columnName]
{
  get
  {
  var result = _validator.Validate(this);
  if (result.IsValid)
  {
    return null;
  }
  return String.Join(Environment.NewLine, 
                     result.Errors.Where(error => error.PropertyName == columnName)
                                  .Select(error => error.ErrorMessage));
  }
}

Since there can be more than one ValidationFailure for a single property, I’m joining them together into a single string with each ErrorMessage in its own line.

This approach causes the Validate method to be called for every binding with ValidatesOnDataErrors enabled. If your validator does a lot of processing, this can add up to a lot of unnecessary validating. To avoid that, the Validate method can instead be called every time a property on the DataContext changes:

private string _name;

public string Name
{
  get { return _name; }
  set
  {
    _name = value;
    Validate();
  }
}

private void Validate()
{
  var result = _validator.Validate(this);
  _errors = result.Errors.GroupBy(error => error.PropertyName)
                         .ToDictionary(group => group.Key, 
                                       group => String.Join(Environment.NewLine,
                                                            group.Select(error => error.ErrorMessage)));
}

The indexer now only needs to retrieve the cached validation results from the _errors Dictionary inside the DataContext:

public string this[string columnName]
{
  get
  {
    string error;
    if (_errors.TryGetValue(columnName, out error))
    {
      return error;
    }
    return null;
  }
}

The only code that doesn’t really belong in the DataContext is now inside the Validate() method. Instead of just calling the Validator, it also parses its results and caches them in a Dictionary for future IDataErrorInfo indexer calls. This can be fixed by extracting the parsing logic into an extension method that can be used from any DataContext:

public static Dictionary<string, string> GroupByProperty(this IEnumerable<ValidationFailure> failures)
{
  return failures.GroupBy(error => error.PropertyName)
                 .ToDictionary(group => group.Key,
                               group => String.Join(Environment.NewLine,
                                                    group.Select(error => error.ErrorMessage)));
}

This makes DataContext’s Validate method much simpler:

private void Validate()
{
  _errors = _validator.Validate(this).Errors.GroupByProperty();
}

The same pattern can be applied for any DataContext with a corresponding Validator. With minor modifications it can be used even in cases when DataContext wraps a model class with its own validator or composites multiple such model classes. This is a quite common scenario when using MVVM pattern.

Monday, July 7, 2014 6:39:33 AM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | WPF
# Wednesday, July 2, 2014

As you might have already noticed, Packt Publishing is currently celebrating 10 years of its existence. During this time they have managed to publish over 2000 books. For this very special occasion they have decided to offer a significant discount on their complete catalog of eBooks and videos – until July 5th all their titles can be purchased for just $10. If you’ve been considering buying one of their titles, now is the right time to do it. If you haven’t, why not browse through their catalog; you might find something that piques your interest.

10 days 10 years - All eBooks & videos for $10

NuGet 2 EssentialsSince I’m also the author of NuGet 2 Essentials, one of the books in their line-up, I encourage you to take a closer look at this book. If you’re a .NET developer, it should be an interesting read to you, no matter how much previous experience you already have with NuGet:

  • If you haven’t used it at all, you need to change that as soon as possible. This book can serve as a great introduction to it.
  • If you already know NuGet basics, the book will teach you, how to take better advantage of it.
  • And if you’re already a proficient user, it will probably still show you a new trick or two.

You can read more about the book in my previous blog post about it or from the publisher’s official page. Of course I’m at least a bit biased as the author, so don’t just take my word for its quality. The reviews have been quite positive as well; feel free to read them here, here, and here. Just don’t take too long: you only have until Saturday to get it at a discounted price.

Wednesday, July 2, 2014 4:01:40 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback

# Monday, June 30, 2014

XAML has first class syntax support for binding to indexed properties, such as Dictionary. It’s even possible to use FallbackValue to handle missing keys in the collection:

<TextBox Text="{Binding Dictionary[MissingKey], FallbackValue='Error'}" />

Of course, real properties still have their advantages over indexed ones, such as full support for implementing INotifyPropertyChanged. For Dictionary properties there is no way to raise PropertyChanged for a single item in the collection. It can only be done for the Dictionary property which means notification for all items in the collection at once.

private IDictionary<string, string> _dictionary;
public IDictionary<string, string> Dictionary
{
  get { return _dictionary; }
  set
  {
    _dictionary = value;
    OnPropertyChanged();
  }
}

viewModel.Dictionary = new Dictionary<string, string>
{ 
  {"Key", "New Value"},
  // ...
};

This brings some performance overhead, except for scenarios where the complete Dictionary is being reconstructed at the same time, any way.

Unfortunately, while this approach works great and doesn’t cause any issues whatsoever in WPF, in WinRT (i.e. Windows Store applications) raising PropertyChanged for the Dictionary causes problems when there are bindings to keys that are not present in the new Dictionary. The KeyNotFoundException thrown by it, when the binding tries to access the non-existent item, remains unhandled and causes the application to crash.

Unhandled exception

Having FallbackValue set doesn’t help. Obviously the exception gets caught in application level UnhandledException handler, i.e. you can handle it there:

void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
  e.Handled = true;
}

You’ll usually want to be more selective when handling exceptions here and even add some type of logging or error reporting for other caught exceptions. Even if you add such a handler, your application will still break in debug mode, unless you add the following conditional compilation symbol to your project: DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION (which can also be seen in the above screenshot).

Because of all this, you might still want to handle the exception in some other way in Windows Store applications. A standard approach would be a custom IValueConverter:

public class DictionaryConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, string language)
  {
    var dictionary = value as Dictionary<string, string>;
    if (dictionary == null || !(parameter is string))
    {
      return null;
    }
    string result;
    dictionary.TryGetValue((string)parameter, out result);
    return result;
  }

  public object ConvertBack(object value, Type targetType, object parameter, string language)
  {
    return null;
  }
}

The obvious advantages of it are simplicity and no changes to the view model. The price for this is a slight performance hit caused by the converter and more complex XAML syntax:

<TextBox Text="{Binding Dictionary, Converter={StaticResource DictionaryConverter},
                                    ConverterParameter=MissingKey}" />

Alternatively the Dictionary indexer could be replaced with a different one, returning null instead of throwing exceptions when the key is not present. The original Dictionary could be wrapped in a custom IDictionary implementation:

public class NonThrowingDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
  private readonly Dictionary<TKey, TValue> _dictionary;

  public NonThrowingDictionary(Dictionary<TKey, TValue> dictionary)
  {
    _dictionary = dictionary;
  }

  public TValue this[TKey key]
  {
    get
    {
      TValue value;
      _dictionary.TryGetValue(key, out value);
      return value;
    }
    set
    {
      _dictionary[key] = value;
    }
  }
  
  // Implement other members by passing calls to _dictionary
}

Now this dictionary could be used in the view model instead of the original one. To reduce the amount of extra code, only the indexer property could be implemented:

public class DictionaryWrapper<TKey, TValue>
{
  private readonly Dictionary<TKey, TValue> _dictionary;

  public DictionaryWrapper(Dictionary<TKey, TValue> dictionary)
  {
    _dictionary = dictionary;
  }

  public TValue this[TKey key]
  {
    get
    {
      TValue value;
      _dictionary.TryGetValue(key, out value);
      return value;
    }
    set
    {
      _dictionary[key] = value;
    }
  }
}

Either way requires more code than the IValueConverter approach and has greater impact on the view model. On the other hand XAML markup remains unchanged and there are some performance benefits since the converter isn’t called every time the binding is refreshed.

Depending on your requirements and values you can choose whichever approach best fits your case.

Monday, June 30, 2014 8:36:25 AM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Metro | Windows Store | WPF
My Book

NuGet 2 Essentials

About Me
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

All Content © 2014, Damir Arh, M. Sc. Send mail to the author(s) - Privacy Policy - Sign In
Based on DasBlog theme 'Business' created by Christoph De Baene (delarou)
Social Network Icon Pack by Komodo Media, Rogie King is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.