Forcing Derived type to apply custom attribute

Introduction

This article illustrates options to force attributes on derived types.

Background

In .NET eco system, Attributes are not inheritable. This means any attribute applied on base class are not applied/inherited on derived class. This article looks at different options available to forcer the attributes on derived types at compile time and at run time.

Approach

There are two approaches (with different intensions)

1. Forcing at run time : The base class constructor code will check for the presence of attribute and throw error runtime if attribute is not changed.

2. Forcing at compile time: Using ObsoleteAttribute, the Mandatory attribute will be reflected at compile time and will raise the error. This information is taken from this question on Stackoverflow.com

Using the Code

Forcing attribute at run time

  1. Creating a Custom Attribute
    class CustomAttribute : System.Attribute { }  
  2. In the constructor of base check the attribute
     publicBase() { CheckCustomAttribute(); } 
  3. If class type is base, skip the attribute check
     if (!(this.GetType() == typeof(Base))) 
  4. If class is derived type, check whether attribute exists or not.
    var attr = System.Attribute.GetCustomAttributes(
                             this.GetType())
                            .SingleOrDefault(t => typeof(CustomAttribute)
                            .IsAssignableFrom(t.GetType()));
    
  5. The IsAssignableFrom take care of any attribute that derives from CustomAttribute.

  6. Throw error is attribute does not exist.
    if (attr == null)
     {
         throw new Exception(String.Format(
                             "Derived class {0} doesnot apply {1} attribute",
                             this.GetType().Name,
                             typeof(CustomAttribute).Name));
     }

Forcing attribute at compile time

There is a special attribute ObsoleteAttribute. It is sealed so cannot be subclassed. The C# compiler has special handling for this attribute.

However to use Obsolete attribute rather awkwardly, It can be applied to a custom attribute. Then applying that custom attribute (on class/structs) will force compiler to show error

  1. Create a custom attribute
    public class MandatoryAttribute : Attribute{}
    
  2. Decorate the custom attribute with ObsoleteAttribute
    [Obsolete("MandatoryAttribute is required", true)]
    public class MandatoryAttribute : Attribute{}
    

     

  3. Apply Custom attribute to class/member to get notification (as compile time error) on any type
    //[MandatoryAttribute]
    public class Base
    {
     //[MandatoryAttribute]
     public void SayHello() {}
    }
    

Uncommenting MandatoryAttribute raises awkard compile time error.

This is awkawrd because the error message is like

“MandatoryAttribute’ is obsolete: ‘MandatoryAttribute is required’    <filename>    <projectname>’”

Download source code from src link for this post.

Fast CSV Row Count using Binary Reader

Introduction

The code snippet in this article illustrates an efficient/fast row/line count algorithm using BinaryReader API.

Background

CSV file format has text data. There is no official restriction on number of rows, number of columns or file size. 

RFC4180 Format

Due to no restriction, to read number of lines, complete file reading is required.

Using the code

In windows operating system Line break is represented by CR LF \r \n .

The basic approach is to read all the content through streaming, and find for the Line breaks.

BinaryReader API is used for stream read. This class  reads primitive data types as binary values in a specific encoding.

private static int GetLineCount(string fileName)
{
    using (FileStream fs = File.OpenRead(fileName))
    using (BinaryReader reader = new BinaryReader(fs))
    {
       int lineCount = 0;

       char lastChar = reader.ReadChar();
       char newChar = new char();

      do
      {
        newChar = reader.ReadChar();
        if (lastChar == '\r' &amp;&amp; newChar == '\n')
        {
          lineCount++;
        }
        lastChar = newChar;
      } while (reader.PeekChar() != -1);
      return lineCount;
}

Alternatives:

  1. Read all records at a time, and calculate the Array Length using File.ReadAllLines API. This is good for small files. For large files (>2GB) OutOfMemoryException is expected.
  2. StreamReader API: There are 2 options
    1. using ReadLine function to read lines. This has trade-off of line to string conversion which is not needed.
    2. using Read() and Peek() method. This is similar to using BinaryReader approach but these methods return integer and not char so little bit more logic is required for character comparisons.

Points of Interest

Below are some efficient CSV parsers I have come across/used.

  1. TextFieldParser : This is built-in .NET structured text file parser. This parser is placed in Microsoft.VisualBasic.dll library.
  2. KBCsv library: This is efficient, easy to use library developed by Kent Boogaart.

Closing View from ViewModel

Introduction 

This short article presents a walk-through to close WPF application from View Model.

Background

Closing/starting a window is UI interaction(owned by view) and should to be decoupled from view model. View model should contain Commands, and Properties (as needed for the view).

View model can also contain events, to which view can respond. In the approach presented in this article, view model event is used to trigger an action owned by view.

There are already multiple approach to this problem.

  1. Using Attached Behavior
  2. Using Application level service/controller to manage application life cycle
  3. Using Message Bus (like MVVM Light Messenger/Prism Event Aggregator)

The approach mentioned in the article is trimmed down version of above approaches for a small WPF application (where Attached Behavior and Application service are overkill).

Approach    

In this approach, a RequestClose event will be added to ViewModel.   View model will raise RequestClose event and view will respond to it by invoking Close method.

The event wire up and view-viewmodel binding is done in Application startup override.

Using the code   

The code is written in VS2012 RTM.   It should be opened in VS2010/VS2012RTM/VS2012 as visual studio projects / solutions are now backword compatible. The application uses MVVM Light (for MVVM base framework).

Demo application contains a single window, with a button “Close Me”. Clicking on this button invokes CloseCommand on view model that in-turns raises RequestClose event.  The view handler then closes the instance (on listening RequestClose event).

  1. Create ICloseable interface that defines RequestClose event. ViewModel should implement ICloseable interface if it supportes Closeable behavior.
  2. interface ICloseable
    {
       event EventHandler RequestClose;
    }
    
  3. Implement ICloseable to the view model.
  4. class MainWindowViewModel : ViewModelBase, ICloseable
    
  5. Add CloseCommand to the view model.
  6. public ICommand CloseCommand { get; private set; }
    
  7. Wire-up RequestClose event in the Loaded event of View code behind, if DataContext implementsICloseable interface.
  8. Loaded += (s, e) =>
      {
        if (DataContext is ICloseable)
        {
            (DataContext as ICloseable).RequestClose += (_, __) => this.Close();
        }
      };
    
  9. View-viewmodel binding is done in Application Startup.
  10. protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
    
        // Create Main Window instance
        MainWindow window = new MainWindow();
    
        // Create Main Window View Model
        MainWindowViewModel viewModel = new MainWindowViewModel();
    
        // Associate DataContext
        window.DataContext = viewModel;
    
        Application.Current.MainWindow = window;
        window.Show();
    }
    
  11. StartupURI should be removed from MainWindow.xaml.

Here is attached code. (Rename extension from doc to zip. It is a wordpress limitation)

Points of Interest

Following refinements are useful:

  1. View view model binding can be moved from OnStartup to ViewModelLocator.  Refer to this blog for View ViewModel binding approaches.
  2. Event wire-up can be refreshed on DataContext change notification.

Managing multiple selection in View Model ( .net Metro style app)

I was into refactoring of some WPF code (of metro application) into MVVM design pattern that has heavily used code behind.

I was stumbled upon a requirement, to bind to Selected Items property of GridView.  There was a list view in snapped mode and grid view in other modes (full/fill).

Requirement:

All I was trying to do is below

  1. To define SelectedItems in ViewModel
  2. Bind GridView.ItemsSource, ListView.ItemsSource to Items
  3. Somehow bind SelectedItems of GridView and ListView to SelectedItems
  4. After step 3, hoping that any selection change in GridView should be reflected to ListView and vice versa.

Challenges:

Never faced this scenario before, I found following challenges

  1. SelectedItems property is read only, and cannot be set directly
  2. SelectedItems cannot be used for binding expression, hence cannot be retrieved in View Model
  3. WinRT has no support for Behaviors. (For some unknown reasons, I wanted to use Attached Behavior). Thankfully there exists WinRTBehaviors on codeplex.

Note – Behaviors are not supported in WinRT natively. WinRTBehaviors is an open source for providing behavior support. This library is excellent, and provides behavior extension, exactly similar to WPF framework.

Behavior outline

  1. Behavior name -> MultiSelectBehavior. It will target ListViewBase (why -> Base class that provides Multiple selection mechanism)
  2. Add SelectedItems Dependency property to Behavior. This property will track of selected items of associated UI Element (List view derived class is referred as UI Element from hereafter).
  3. Hookup SelectionChanged event of UI element in  OnAttached, OnDetached event of Behavior. In the OnSelectionChanged event, sync up the changes to SelectedItems (of Behavior). It will propatege UI selection changes to SelectedItems in MultiBehavior.
  4. In the Property changed callback of SelectedItems (in Behavior), listen to CollectionChanged of bound object. Propagate changes in CollectionChanged event to UI Element.
  5. Add Behavior to UI elements in XAML
  6. Define data binding from SelectedItems (in Behavior) to SelectedItems in view model.

Code walkthrough

ListView, GridView are inherited from ListViewBase. ListViewBase provides multiple selection mechanism (SelectedItems, SelectionMode properties).

MultiSelectBehavior class is defined that is targeting ListViewBase.


public class MultiSelectBehavior : Behavior

SelectedItems dependency property is created in MultiSelectBehavior class. It internally holds all the selected items in the ListViewBase derived class.

public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
 "SelectedItems",
 typeof(ObservableCollection</pre>
SelectionChanged event is hooked up in the Behavior

1
protected override void OnAttached()
 {
 base.OnAttached();
 AssociatedObject.SelectionChanged += OnSelectionChanged;
 }

protected override void OnDetaching()
 {
 base.OnDetaching();
 AssociatedObject.SelectionChanged -= OnSelectionChanged;
 }

When SelectionChanged is triggered on element, SelectedItems is populated. _selectionChangedInProgress flag indicates, the selection change is in process. If this flag is set, no further handling is done (as it would trigger to infinite loop and stackoverflow exception).

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
 {
 if (_selectionChangedInProgress) return;
 _selectionChangedInProgress = true;
 foreach (var item in e.RemovedItems)
 {
 if (SelectedItems.Contains(item))
 {
 SelectedItems.Remove(item);
 }
 }

foreach (var item in e.AddedItems)
 {
 if (!SelectedItems.Contains(item))
 {
 SelectedItems.Add(item);
 }
 }
 _selectionChangedInProgress = false;
 }

Hook the collection change event of bound ObservableCollection. Propagate any change to List view base derived ui elements. This is done in PropertyChangedCallback handler.

 private static void PropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
 {
 NotifyCollectionChangedEventHandler handler = (s, e) => SelectedItemsChanged(sender, e);
 if (args.OldValue is ObservableCollection<object>)
 {
 (args.OldValue as ObservableCollection<object>).CollectionChanged -= handler;
 }

if (args.NewValue is ObservableCollection<object>)
 {
 (args.NewValue as ObservableCollection<object>).CollectionChanged += handler;
 }
 }

private static void SelectedItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
 {
 if (sender is MultiSelectBehavior)
 {
 var listViewBase = (sender as MultiSelectBehavior).AssociatedObject;

var listSelectedItems = listViewBase.SelectedItems;
 if (e.OldItems != null)
 {
 foreach (var item in e.OldItems)
 {
 if (listSelectedItems.Contains(item))
 {
 listSelectedItems.Remove(item);
 }
 }
 }

if (e.NewItems != null)
 {
 foreach (var item in e.NewItems)
 {
 if (!listSelectedItems.Contains(item))
 {
 listSelectedItems.Add(item);
 }
 }
 }
 }
 }
 

MultiSelectBehavior is now completed.

Apply the behavior to UI elements.
Import the namespaces in XAML ( i -> behavior framework library, custom -> MultiSelectBehavior class)

 xmlns:i ="using:WinRtBehaviors"
 xmlns:custom="using:WinRtExt.Behavior"

Add behavior, and attach bind SelectedItems of behavior to SelectedItems of ViewModel


<i:Interaction.Behaviors>
 <custom:MultiSelectBehavior SelectedItems="{Binding SelectedItems, Mode=TwoWay}">

 </custom:MultiSelectBehavior>
 </i:Interaction.Behaviors>

Following XAML is for 2 controls (one list view, other grid view)


<GridView SelectionMode="Multiple" ItemsSource="{Binding Items}" BorderBrush="White" BorderThickness="2" ItemTemplate="{StaticResource textBlockDataTemplate}">
 <i:Interaction.Behaviors>
 <custom:MultiSelectBehavior SelectedItems="{Binding SelectedItems, Mode=TwoWay}">

 </custom:MultiSelectBehavior>
 </i:Interaction.Behaviors>
 </GridView>
 <Rectangle Width="20"></Rectangle>
 <ListView SelectionMode="Multiple" ItemsSource="{Binding Items}" BorderBrush="White" BorderThickness="2" ItemTemplate="{StaticResource textBlockDataTemplate}">
 <i:Interaction.Behaviors>
 <custom:MultiSelectBehavior SelectedItems="{Binding SelectedItems, Mode=TwoWay}">
 </custom:MultiSelectBehavior>
 </i:Interaction.Behaviors>
 </ListView>

Both list view and grid view are multi select enabled and in sync. Any selection change in any control is propagated to other control.

MultiselectSample is attached code. (Rename extension from doc to zip. It is a wordpress limitation).

The code is written in VS2012 RC in Win 8 Release preview. (It is incompatible with older versions, Win 8 Consumer preview, Win 8 developer preview, and may get broken in future versions).

Follow

Get every new post delivered to your Inbox.