Donnerstag, 27. Dezember 2012

NFC tags with Windows Phone 8

Today I have ordered my first NFC tags to try this amazing new technology which comes with Windows Phone 8. To get started I found some very good websites  which explains the NFC technology and contains several samples for writing and reading NFC tags.

If you plan to work with NFC tags consider the following points. Especially if you order NFC tags, check if they support the NDEF standard and the tags are already formatted.

  • You cannot enable the write lock.
  • You cannot format a tag. Your tag must be formatted for NDEF message.
  • Your tag can contain only an NDEF message.
  • You cannot use all tag memory. NDEF formatting data and other private tag data take memory. Because of the fact that a tag has only a few bytes of memory, this data size is important. For example, you can only write 716 bytes on a tag with a memory of 1024 bytes and 454 bytes on a tag with a memory of 512 bytes.
  • Proximity API does not give tools to manipulate directly NDEF messages. To manipulate raw NDEF messages you can use NDEF Library for Proximity APIs (NFC).
  • You cannot receive or write a tag when your application runs in background.

Detail information about NFC on Windows Phone 8 you could found here:

Samstag, 22. Dezember 2012

Windows Phone 8 Why no official calendar control?

Last night I have tried several calendar controls for my Windows Phone 8 time sheet app, but no one matches my requirements and looks like the core calendar of Windows Phone 8. So what to do as a developer if you cannot find anything useful and not willing to use a third party control: write it by your own .-)

The result of a short night is this:

wp_ss_20121222_0001

If I found time to generalize the code, I will post it the next time here.

Windows Phone 8 Easy and intuitive way for validation using INotifyDataErrorInfo

Code should be transparent and intuitive for other developers to read. Therefore I searched for my current project – a Windows Phone 8 app to manage time sheets - a good solution to implement validation rules for my entities at a central point in my models. I found a nice implementation of a BindingModel from outcoldman at Codeproject. He looks at several validation technologies we have with Silverlight and describes them in the mentioned article in detail. Most of my classes based on this article which I have expanded by some new behaviors and properties.

My resulting validation code in the constructor of my models looks like this:

 

AddValidationFor(() => CustomerName)
        .When(x => string.IsNullOrEmpty(x._customerName))
        .Show(AppResources.InvalidNotNullOrEmpty);
 
AddValidationFor(() => OrderName)
    .When(x => string.IsNullOrEmpty(x._orderName))
    .Show(AppResources.InvalidNotNullOrEmpty);
 
AddValidationFor(() => Name)
    .When(x => string.IsNullOrEmpty(x._name))
    .Show(AppResources.InvalidNotNullOrEmpty);
 
AddValidationFor(() => ProjectHoursMax)
    .When(x => x._projectHoursMax <= 0 && x._billType == BillType.Billable)
    .Show(AppResources.InvalidZeroNotAllowed);
 
AddValidationFor(() => Start)
    .When(x => x._end <= x._start)
    .Show(AppResources.InvalidStartIsGreaterThanEnd);

 


The basics

The INotifyDataErrorInfo interface came with Silverlight 4 which can be used for  synchronous and asynchronous validation. Microsoft suggestion is, that new entity classes should implement INotifyDataErrorInfo for the added flexibility instead of implementing IDataErrorInfo. The IDataErrorInfo support enables you to use many existing entity classes that are written for the full .NET Framework.

 

Let’s start

The first step of the validation rule implementation is to expand our properties for storing validation rules and manage error messages.This is done by the PropertyValidation class:

/// <summary>
/// Add validation support to properties 
/// </summary>
/// <typeparam name="TBindingModel">Model to bind</typeparam>
public class PropertyValidation<TBindingModel>
    where TBindingModel : BindingModelBase<TBindingModel>
{
    private Func<TBindingModel, bool> _validationCriteria;
    private string _errorMessage;
    private readonly string _propertyName;
 
    public PropertyValidation(string propertyName)
    {
        _propertyName = propertyName;
    }
 
    public PropertyValidation<TBindingModel> When(Func<TBindingModel, bool> validationCriteria)
    {
        if (_validationCriteria != null)
            throw new InvalidOperationException("You can only set the validation criteria once.");
 
        _validationCriteria = validationCriteria;
        return this;
    }
 
    public PropertyValidation<TBindingModel> Show(string errorMessage)
    {
        if (_errorMessage != null)
            throw new InvalidOperationException("You can only set the message once.");
 
        _errorMessage = errorMessage;
        return this;
    }
 
    public bool IsInvalid(TBindingModel presentationModel)
    {
        if (_validationCriteria == null)
            throw new InvalidOperationException(
                "No criteria have been provided for this validation. (Use the 'When(..)' method.)");
 
        return _validationCriteria(presentationModel);
    }
 
    public string GetErrorMessage()
    {
        if (_errorMessage == null)
            throw new InvalidOperationException(
                "No error message has been set for this validation. (Use the 'Show(..)' method.)");
 
        return _errorMessage;
    }
 
    public string PropertyName
    {
        get { return _propertyName; }
    }
}

The next step is to implement a generic BindingModelBase class which will implement the INotifyPropertyChanged and INotifyDataErrorInfo interfaces. This class contains also two fields for storing the added validation rules and validation errors:

/// <summary>
/// BindingModel to support validation and handling of error messages
/// (Implements INotifyDataError)
/// </summary>
/// <typeparam name="TBindingModel">Model to bind</typeparam>
public abstract class BindingModelBase<TBindingModel> : INotifyPropertyChanged, INotifyDataErrorInfo
    where TBindingModel : BindingModelBase<TBindingModel>
{
    private readonly List<PropertyValidation<TBindingModel>> _validations = new List<PropertyValidation<TBindingModel>>();
    private Dictionary<string, List<string>> _errorMessages = new Dictionary<string, List<string>>();
 
    protected BindingModelBase()
    {
        PropertyChanged += (s, e) => { if (e.PropertyName != "HasErrors" && e.PropertyName!="ErrorMessages") ValidateProperty(e.PropertyName); };
    }
 
    #region INotifyDataErrorInfo
 
    public IEnumerable GetErrors(string propertyName)
    {
        if (_errorMessages.ContainsKey(propertyName))
            return _errorMessages[propertyName];
 
        return new string[0];
    }
 
    public bool HasErrors
    {
        get { return _errorMessages.Any(); }
    }
 
    public Dictionary<string, List<string>> ErrorMessages
    {
        get { return _errorMessages; }
    }
 
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { };
 
    private void OnErrorsChanged(string propertyName)
    {
        ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }
 
    #endregion
 
    #region INotifyPropertyChanged
 
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
 
    protected void RaisePropertyChanged([CallerMemberName]string propertyName=null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
 
    #endregion
 
    protected void RaisePropertyChanged(Expression<Func<object>> expression)
    {
eSharper disable ExplicitCallerInfoArgument
        if (expression != null) RaisePropertyChanged(GetPropertyName(expression));
eSharper restore ExplicitCallerInfoArgument
    }
 
 
    protected PropertyValidation<TBindingModel> AddValidationFor(Expression<Func<object>> expression)
    {
        return AddValidationFor(GetPropertyName(expression));
    }
 
    protected PropertyValidation<TBindingModel> AddValidationFor(string propertyName)
    {
        var validation = new PropertyValidation<TBindingModel>(propertyName);
        _validations.Add(validation);
 
        return validation;
    }
 
 
    public void ValidateAll()
    {
        var propertyNamesWithValidationErrors = _errorMessages.Keys;
 
        _errorMessages = new Dictionary<string, List<string>>();
 
        _validations.ForEach(PerformValidation);
 
        var propertyNamesThatMightHaveChangedValidation =
            _errorMessages.Keys.Union(propertyNamesWithValidationErrors).ToList();
 
        propertyNamesThatMightHaveChangedValidation.ForEach(OnErrorsChanged);
 
        RaisePropertyChanged(() => HasErrors);
        RaisePropertyChanged(() => ErrorMessages);
    }
 
    public void ValidateProperty(Expression<Func<object>> expression)
    {
        ValidateProperty(GetPropertyName(expression));
    }
 
    private void ValidateProperty(string propertyName)
    {
        _errorMessages.Remove(propertyName);
 
        _validations.Where(v => v.PropertyName == propertyName).ToList().ForEach(PerformValidation);
        OnErrorsChanged(propertyName);
        RaisePropertyChanged(() => HasErrors);
        RaisePropertyChanged(() => ErrorMessages);
    }
 
    private void PerformValidation(PropertyValidation<TBindingModel> validation)
    {
        if (validation.IsInvalid((TBindingModel)this))
        {
            AddErrorMessageForProperty(validation.PropertyName, validation.GetErrorMessage());
        }
    }
 
    private void AddErrorMessageForProperty(string propertyName, string errorMessage)
    {
        if (_errorMessages.ContainsKey(propertyName))
        {
            _errorMessages[propertyName].Add(errorMessage);
        }
        else
        {
            _errorMessages.Add(propertyName, new List<string> { errorMessage });
        }
    }
 
    private static string GetPropertyName(Expression<Func<object>> expression)
    {
        if (expression == null)
            throw new ArgumentNullException("expression");
 
        MemberExpression memberExpression;
 
        if (expression.Body is UnaryExpression)
            memberExpression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
        else
            memberExpression = expression.Body as MemberExpression;
 
        if (memberExpression == null)
            throw new ArgumentException("The expression is not a member access expression", "expression");
 
        var property = memberExpression.Member as PropertyInfo;
        if (property == null)
            throw new ArgumentException("The member access expression does not access a property", "expression");
 
        var getMethod = property.GetGetMethod(true);
        if (getMethod.IsStatic)
            throw new ArgumentException("The referenced property is a static property", "expression");
 
        return memberExpression.Member.Name;
    }
}

 

Show the errors

To show the errors at the user interface I used the ErrorMessages and HasError property. At my View I only have to attach a BindingValidationError event handler which calls an extension method to mark the properties which raises an error.

this.BindingValidationError += TimeSheetEntryPageBindingValidationError;
 
void TimeSheetEntryPageBindingValidationError(object sender, ValidationErrorEventArgs e)
{
    this.HandleBindingValidationError(sender, e);
}
 
public static void HandleBindingValidationError(this PhoneApplicationPage phoneApplicationPage, object sender, ValidationErrorEventArgs e)
{
    var control = e.OriginalSource as Control;
 
    if (control == null) return;
 
    if (e.Action == ValidationErrorEventAction.Added)
    {
 
        control.BorderBrush = new SolidColorBrush(Colors.Red);
 
    }
    else if (e.Action == ValidationErrorEventAction.Removed)
    {
 
        if (control is ListPicker || control is DatePicker || control is TimePicker)
        {
            control.BorderBrush = phoneApplicationPage.Resources["PhoneForegroundBrush"] as SolidColorBrush;
        }
        else
        {
            control.BorderBrush = new SolidColorBrush(Color.FromArgb(0xb, 255, 255, 255));
        }
    }
}

But how to show a list of the error messages for the corresponding fields?

To achieve this, I made a converter (our swiss knife :-) which extracts the error messages from the ErrorMessages property and populate that to a user control which shows the error list for one property (the parameter of the converter contains the bounded property name for which I want to display the error messages).

<toolkit:TimePicker  Grid.Row="1" Grid.Column="0" 
      Margin="0,-6,0,0"
      Style="{StaticResource TimePickerErrorStyle}"
      Value="{Binding SelectedEntry.Start, Mode=TwoWay,  
      ValidatesOnDataErrors=true, NotifyOnValidationError=True}"/>
<userControl:ErrorMessageList Items="{Binding SelectedEntry.ErrorMessages,
             Converter={StaticResource ErrorMessagesConverter}
            ,ConverterParameter=Start}"/>

The converter code:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
   var errors = value as Dictionary<string, List<string>>;
   var errorList = new List<string>();
   if (errors != null && errors.ContainsKey(parameter.ToString()))
   {
       errorList.AddRange(errors[parameter.ToString()]);
   }
 
   return errorList;
}