Monthly Archives: October 2014

More custom configuration in the App.config (using IConfigurationSectionHandler)

In the previous post I outlined how to easily create custom configuration code for accessing section of the App.config file. In some situation you may want to take things a little further, so let’s now look at using the IConfigurationSectionHandler to create the same configuration section.

To review, let’s look at the configuration section we’re going to create

<configSections>
   <section name="FiltersSection" type="RvMonitor.FiltersSection, RvMonitor"/>
</configSections>

<FiltersSection>
   <Filters>
      <add type="Filters.ClassNameFilter, Filters" />
      <add type="Filters.ClassNameFilter, Filters" />
   </Filters>
</FiltersSection> 

So for this example, we’re not going to change this configuration and in fact we’ll keep the code which uses this configuration the same, so this will look like

var filtersSection = (FiltersSection)ConfigurationManager.GetSection("FiltersSection");

The first thing we need to do is create the FiltersSection class which will implement IConfigurationSectionHandler. This requires that we implement the Create method. Now you could return the filter collection from this code instead of the FiltersSection, but I wanted to show how the two techniques would look, code-wise, for the same functionality. So in our Create method we’ll return the FiltersSection, as follows (the code below is the full implementation of the FilterSection, we’ll look at each bit of interest in a minute)

Note: I will not deal with error handling within this code so I can keep it to a minimum

public class FiltersSection : IConfigurationSectionHandler
{
   public FiltersSection()
   {
      Filters = new List<FilterType>();
   }

   public object Create(object parent, object configContext, XmlNode section)
   {
      var serializer = new XmlSerializer(typeof(FilterType));

      foreach (XmlNode node in section.ChildNodes)
      {
         if (node.Name == "Filters")
         {
            foreach (XmlNode filterNode in node.ChildNodes)
            {
               var reader = new XmlNodeReader(filterNode);
               Filters.Add((FilterType)serializer.Deserialize(reader));
            }
         }
      }
      return this;
   }

   public IList<FilterType> Filters { get; private set; }
}

So the obvious (boring bits) are we added a Filters property to the FiltersSection and instantiated it within the constructor, but the interesting stuff is within the Create method.

First off, as noted earlier, I wanted to mimic the behaviour of a previous post. So we return this

Easy custom configuration section in the App.config

There’s a couple of ways to handle configuration sections within the App.config file. The simplest (in my opinion at least) is by inheriting from the ConfigurationSection, ConfigurationElement and so on. The alternative would be to implement the IConfigurationSectionHandler, but that’s for another post.

So here’s a simple scenario…

I have a simple Tibco RV monitor application. My own implementation, of sorts of TIB’s tibrvlisten.exe, but with the ability to log and filter messages etc. So I want to create a simply configuration section for supplying a list of the filters to plugin to the application (similar to the way some IoC libraries work).

Here’s a sample of the App.config that I want

<configSections>
   <section name="FiltersSection" type="RvMonitor.FiltersSection, RvMonitor"/>
</configSections>

<FiltersSection>
   <Filters>
      <add type="Filters.ClassNameFilter, Filters" />
      <add type="Filters.ClassNameFilter, Filters" />
   </Filters>
</FiltersSection> 

Let’s start at outside and work inwards.

So quite obviously (from the configSections) we’re going to require a FiltersSection object. We need to derive our FiltersSection from the system.Configuration.ConfigurationSection class. This class will then have a ConfigurationProperty named Filters, which translates to our Filters element. This will be a collection or more specifically a type derived from the ConfigurationElementCollection. Let’s take a look at the code for the FiltersSection first

public class FiltersSection : ConfigurationSection
{
   [ConfigurationProperty("Filters")]
   [ConfigurationCollection(typeof(FiltersCollection),
      AddItemName = "add", 
      ClearItemsName = "clear", 
      RemoveItemName = "remove")]
   public FiltersCollection Filters
   {
      get { return (FiltersCollection)this["Filters"]; }
   }
}

Before we look at the very simple implementation of FiltersCollection let’s review this code.

The ConfigurationProperty simply defines the name of the element which our collection resides within. The ConfigurationCollection attribute then tells the ConfigurationManager the type of the collection and defines the elements to add, clear and remove items. We’re actually only interested in adding filters, after all you can just remove them from the App.config if you want to clear or remove items. The “add” name can be changed and relates to the add elements within the Filters element of the configuration, i.e.

<add type="Filters.ClassNameFilter, Filters" />

So let’s create a simply ConfigurationCollection

public class FiltersCollection : ConfigurationElementCollection
{
   protected override ConfigurationElement CreateNewElement()
   {
      return new FilterType();
   }

   protected override object GetElementKey(ConfigurationElement element)
   {
      return element;
   }
}

I’ve shown the bare minimum required to implement a ConfigurationElementCollection. Obviously we need some way to create instances of our element type (i.e. that type that our “add” element creates). Here we create a FilterType via the CreateNewElement method. I’ve not bothered creating an element key, so I’m just returning element from GetElementKey, but you might prefer to use something like

protected override object GetElementKey(ConfigurationElement element)
{
   return ((FilterType)element).TypeName;
}

Finally let’s look at the extremely simple FilterType which derives from the ConfigurationElement type.

public class FilterType : ConfigurationElement
{
   [ConfigurationProperty("type", IsRequired = true)]
   public string TypeName
   {
      get { return (string) this["type"]; }
      set { this["type"] = value; }
   }
}

Notice how in this class and the FiltersSection class we use the built in Hashtable to store our actual property data.

And that’s about it, oh, except how to use the code within our app. Here’s the code

var filtersSection = (FiltersSection)ConfigurationManager.GetSection("FiltersSection");

and there we have it, pretty simple.

Dynamic columns within the XamDataGrid

Before I start this post, let me just say I’m using an old version of the Infragistics XamDataGrid for this post, version 10.3. Hence this may have been changed in subsequent releases, but as I have a legacy application to support, that’s the version they’re using.

In the past few posts I’ve been looking at implementing a hierarchical data model and displaying it using the XamDataGrid is a similar way to a tree view might work. For the project I’m currently working on we also have the requirement to display an unknown number of columns.

If we take the previous examples where we had the following view model

public class EmployeeViewModel
{
   public EmployeeViewModel()
   {
      Manages = new ObservableCollection<EmployeeViewModel>();
   }

   public string Name { get; set; }
   public ObservableCollection<EmployeeViewModel> Manages { get; private set; }
}

Let’s assume each employee will need to take an unspecified number of courses each year. Some employees might need to take one group of courses whilst others may take another group of courses but we want to see them all listed against each employee.

Ofcourse we could simply add an ObservableCollection with every available course stored for each employee within this list, but this may be neither feasible or desirable.

Another alternative might be to use a DataTable and obviously populate this as necessary.

But I’m going to implement this functionality all inside a our XamDataGrid derived class. As we’re already handling similar changes in code for the hierarchical data, I don’t feel too dirty writing more code.

Let’s see the code

The view model will looks as follows

public class CourseViewModel
{
   public string Name { get; set; }
   public double Score { get; set; }
}

public class EmployeeViewModel
{
   public EmployeeViewModel()
   {
      Manages = new ObservableCollection<EmployeeViewModel>();
      Courses = new ObservableCollection<CourseViewModel>();
   }

   public string Name { get; set; }
   public ObservableCollection<EmployeeViewModel> Manages { get; private set; }
   public ObservableCollection<CourseViewModel> Courses { get; private set; }

   public double? this[string course]
   {
      get
      {
         var result = Courses.FirstOrDefault(c => c.Name == course);
         return result == null ? (double?)null : result.Score;
      }
   }
}

The key additions to the previous implementation of the EmployeeViewModel (from previous posts) is the addition of the Courses collection, but more interesting is the addition of the indexer. This will be used when the XamDataGrid is after the Score for the Course for the specific column of data.

In the code behind, we’ll declare the following (at the class level)

private readonly IList<Field> dynamicParentFields = new List<Field>();
private readonly IList<Field> dynamicChildFields = new List<Field>();

private readonly List<string> courses = new List<string>();

private readonly IValueConverter courseValueConverter;

and within the constructor of the code behind class we’ll have the following (after the DataContext has been assigned)

courseValueConverter = new CourseValueConverter();

TraverseCourses((IList<EmployeeViewModel>) DataContext);
courses.Sort();

and here’s the rest of the methods in the code behind

private void TraverseCourses(IEnumerable<EmployeeViewModel> employees)
{
   if (employees == null)
      return;

   foreach (var employee in employees)
   {
      TraverseCourses(employee.Manages);
      foreach (var course in employee.Courses)
      {
         if (courses.FirstOrDefault(c => c == course.Name) == null)
         {
            courses.Add(course.Name);
         }
      }
   }			
}

private void AddDynamicFields(FieldLayout layout, IList<Field> fields)
{
   foreach (var field in fields)
   {
      layout.Fields.Remove(field);
   }
   fields.Clear();

   var rootPropertyPath = new PropertyPath("");

   foreach (var course in courses)
   {
      var field = CreateDynamicField(rootPropertyPath, course);
      layout.Fields.Add(field);
      fields.Add(field);
   }
}

private UnboundField CreateDynamicField(PropertyPath rootPropertyPath, string course)
{
   return new UnboundField
   {
      Name = course,
      Label = course,
      DataType = typeof(object),
      Binding = new Binding
      {
         Path = rootPropertyPath,
         Mode = BindingMode.OneWay,
         Converter = courseValueConverter,
         ConverterParameter = course
      },
      Settings =
      {
         AllowEdit = false,
         LabelTextAlignment = TextAlignment.Center,
         EditorType = typeof(XamTextEditor)
      },
   };
}

and one more thing in the code behind, we need to alter the AssigningFieldLayoutToItem method that we created a event handler off of in the previous posts, it will now look like this

private void grid_AssigningFieldLayoutToItem(object sender, 
            AssigningFieldLayoutToItemEventArgs e)
{
   if (e.Item != null)
   {
      AddDynamicFields(grid.FieldLayouts["parent"], dynamicParentFields);
      AddDynamicFields(grid.FieldLayouts["child"], dynamicChildFields);

      e.FieldLayout = 
          e.ParentExpandableFieldRecord == null ? 
          grid.FieldLayouts["parent"] : 
          grid.FieldLayouts["child"];
   }
}

The final piece of the jigsaw is the CourseValueConverter which looks like this

public class CourseValueConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      if (value is EmployeeViewModel && parameter is string)
      {
         var result = value as EmployeeViewModel;
         var course = (string)parameter;
         return result[course];
      }
      return null;
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

How does this work

So basically at some point after the model has been created, we traverse the EmployeeViewModel tree and get all distinct course names. Obviously in a production environment we’ll also need to handle data changes on the DataContext to ensure we refresh this list as needed.

During the AssigningFieldLayoutToItem event we populate the field layouts (in this sample we’ve restricted the code to the two known field layouts, ofcourse you may need to handle this more generically).

The AddDynamicField method clears any dynamic fields that we’ve created (we keep track of those fields in the dynamicParentFields and dynamicChildFields lists), then we create new Unbound fields for each dynamic field, we assign a converter and pass in the field name (in this case the course name).

The converter does the real work. It’s passed the current EmployeeViewModel by the XamDataGrid, from this it calls the EmployeeViewModel indexer with the parameter (the course name) assigned to the field. Ofcourse we could replace the indexer with a method if we preferred.

Finally the instance of the EmployeeViewModel then checks it’s courses collection for the supplied course and if it’s got it, returns a value, in this case the score.

If our data looked as follows

public static class EmployeeViewModelFactory
{
   public static ObservableCollection<EmployeeViewModel> Create()
   {
      var employees = new ObservableCollection<EmployeeViewModel>();

      var bob = new EmployeeViewModel { Name = "Bob" };
      var bill = new EmployeeViewModel { Name = "Bill" };
      var fred = new EmployeeViewModel { Name = "Fred" };
      var alfred = new EmployeeViewModel { Name = "Alfred" };
      var jim = new EmployeeViewModel { Name = "Jim" };
      var jeff = new EmployeeViewModel { Name = "Jeff" };
      var craig = new EmployeeViewModel { Name = "Craig" };

      bob.Courses.Add(new CourseViewModel { Name = "C2", Score = 100 });
      bob.Courses.Add(new CourseViewModel { Name = "C4", Score = 85 });

      craig.Courses.Add(new CourseViewModel { Name = "C1", Score = 98 });
      craig.Courses.Add(new CourseViewModel { Name = "C4", Score = 65 });

      jeff.Courses.Add(new CourseViewModel { Name = "C3", Score = 70 });

      bob.Manages.Add(bill);
      bob.Manages.Add(fred);

      alfred.Manages.Add(jim);

      jim.Manages.Add(jeff);

      employees.Add(bob);
      employees.Add(alfred);
      employees.Add(craig);

     return employees;
   }
}

our view will now look like this

Dynamically added columns

Addendum

Whilst the above code works, at this point I would tend towards creating my own XamDataGrid derived class and implementing most/all the functionality in that class instead of the code behind. There may be alternate ways to achieve this, I’ve heard of people creating behaviors for the XamDataGrid to handle the creation of the dynamic columns.

Indenting column data in hierarchical data in the XamDataGrid

Before I start this post, let me just say I’m using an old version of the Infragistics XamDataGrid for this post, version 10.3. Hence this may have been changed in subsequent releases, but as I have a legacy application to support, that’s the version they’re using.

So in my previous blog posts on displaying hierarchical data within the XamDataGrid I demonstrated how to get the grid to look a little like a tree view, i.e. show the data in aligned columns etc. but I also mentioned that it wasn’t yet good enough as the child nodes are not indented.

So let’s look at how we might indent the child nodes so that they look more like a tree view and differentiate between child nodes and parent nodes.

What we want to do is change this

Before indentation

to this

After indentation

Here’s a reminder of how our XAML looked at the end of the previous post

<igDP:XamDataGrid DataSource="{Binding}" GroupByAreaLocation="None" x:Name="grid"
   FieldPositionChanged="Grid_OnFieldPositionChanged">
   <igDP:XamDataGrid.Resources>
      <Style TargetType="{x:Type igDP:LabelPresenter}">
         <EventSetter Event="SizeChanged" Handler="EventSetter_OnHandler"/>
      </Style>
   </igDP:XamDataGrid.Resources>

   <igDP:XamDataGrid.FieldLayoutSettings>
      <igDP:FieldLayoutSettings ExpansionIndicatorDisplayMode="CheckOnDisplay"
         AutoGenerateFields="False"/>
   </igDP:XamDataGrid.FieldLayoutSettings>
   <igDP:XamDataGrid.FieldLayouts>

      <igDP:FieldLayout Key="parent">
         <igDP:FieldLayout.Fields>
            <igDP:Field Name="Name" />
            <igDP:Field Name="Manages" Visibility="Hidden" />
         </igDP:FieldLayout.Fields>
      </igDP:FieldLayout>

      <igDP:FieldLayout Key="child">
         <igDP:FieldLayout.Settings>
            <igDP:FieldLayoutSettings LabelLocation="Hidden" 
                 DataRecordPresenterStyle="{StaticResource childDataRecordStyle}"/>
         </igDP:FieldLayout.Settings>
         <igDP:FieldLayout.Fields>
            <igDP:Field Name="Name"/>
             <igDP:Field Name="Manages" Visibility="Hidden" />
         </igDP:FieldLayout.Fields>
      </igDP:FieldLayout>

   </igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>

We’ve already used a value converter once, to align the columns, we’re going to use the same technique now to indent our cell data. Here’s the convert code

public class ChildCellValueConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      return value == null ? Binding.DoNothing : new Thickness((((int)value / 2) * 17), 0, 0, 0);
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

Now let’s implement the resource code in XAML

<controls:ChildCellValueConverter x:Key="childCellValueConverter" />

<Style x:Key="childCellValueStyle" TargetType="{x:Type igDP:CellValuePresenter}">
   <Setter Property="Margin" Value="{Binding NestingDepth, Converter={StaticResource childCellValueConverter}}"/>
</Style>

and finally we need to update the field layout (for the “child”) to add the following (within the Field “Name” element

<igDP:Field.Settings>
   <igDP:FieldSettings CellValuePresenterStyle="{StaticResource childCellValueStyle}" />
</igDP:Field.Settings>

and there we have it. Now the child records indent.

Note: Unfortunately the solution to displaying the child nodes offset from the parent nodes is not perfect. You may notice white space where text should be for some rows. If I come up with a solution I’ll update this post accordingly.

Solving the display of alternate layouts for hierarchical view model in the XamDataGrid

Before I start this post, let me just say I’m using an old version of the Infragistics XamDataGrid for this post, version 10.3. Hence this may have been changed in subsequent releases, but as I have a legacy application to support, that’s the version they’re using.

From previous posts you’ll notice we had to create an altered view of our preferred view model, i.e. we should just have an EmployeeViewModel which has a property, named Manages, which is itself a collection of EmployeeViewModel objects, instead we ended up creating a ManagerViewModel and EmployeeViewModel (please refer to the previous posts for more info). So I want to use the following view model now (and fix this problem with field layouts)

public class EmployeeViewModel
{
   public EmployeeViewModel()
   {
      Manages = new ObservableCollection<EmployeeViewModel>();
   }

   public string Name { get; set; }
   public ObservableCollection<EmployeeViewModel> Manages { get; private set; }
}	

and just for completeness, here’s a factory to show our sample data

public static class EmployeeViewModelFactory
{
   public static ObservableCollection<EmployeeViewModel> Create()
   {
      var employees = new ObservableCollection<EmployeeViewModel>();

      var bob = new EmployeeViewModel { Name = "Bob" };
      var bill = new EmployeeViewModel { Name = "Bill" };
      var fred = new EmployeeViewModel { Name = "Fred" };
      var alfred = new EmployeeViewModel { Name = "Alfred" };
      var jim = new EmployeeViewModel { Name = "Jim" };
      var jeff = new EmployeeViewModel { Name = "Jeff" };
      var craig = new EmployeeViewModel { Name = "Craig" };

      bob.Manages.Add(bill);
      bob.Manages.Add(fred);

      alfred.Manages.Add(jim);

      jim.Manages.Add(jeff);

      employees.Add(bob);
      employees.Add(alfred);
      employees.Add(craig);

      return employees;
   }
}

So here’s the XAML we’d like to use

<igDP:XamDataGrid DataSource="{Binding}" GroupByAreaLocation="None" x:Name="grid"
      FieldPositionChanged="Grid_OnFieldPositionChanged">
   <igDP:XamDataGrid.Resources>
      <Style TargetType="{x:Type igDP:LabelPresenter}">
         <EventSetter Event="SizeChanged" Handler="EventSetter_OnHandler"/>
      </Style>
  </igDP:XamDataGrid.Resources>

  <igDP:XamDataGrid.FieldLayoutSettings>
     <igDP:FieldLayoutSettings ExpansionIndicatorDisplayMode="CheckOnDisplay"
           AutoGenerateFields="False"/>
     </igDP:XamDataGrid.FieldLayoutSettings>
     <igDP:XamDataGrid.FieldLayouts>
                
        <igDP:FieldLayout>
           <igDP:FieldLayout.Fields>
              <igDP:Field Name="Name" />
              <igDP:Field Name="Manages" Visibility="Hidden" />
           </igDP:FieldLayout.Fields>
        </igDP:FieldLayout>

        <igDP:FieldLayout>
           <igDP:FieldLayout.Settings>
              <igDP:FieldLayoutSettings LabelLocation="Hidden" />
           </igDP:FieldLayout.Settings>
           <igDP:FieldLayout.Fields>
              <igDP:Field Name="Name" />
              <igDP:Field Name="Manages" Visibility="Hidden" />
           </igDP:FieldLayout.Fields>
       </igDP:FieldLayout>
                
    </igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>

and finally here’s the code behind

private void EventSetter_OnHandler(object sender, SizeChangedEventArgs e)
{
   var lp = sender as LabelPresenter;
   if (lp != null)
   {
      if (grid.FieldLayouts[0].Fields.Contains(lp.Field))
      {
         var f = grid.FieldLayouts[1].Fields[lp.Field.Index];
         f.Width = new FieldLength(lp.Field.CellWidthResolved);
      }

      if (grid.FieldLayouts[1].Fields.Contains(lp.Field))
      {
         var f = grid.FieldLayouts[0].Fields[lp.Field.Index];
         f.Width = new FieldLength(lp.Field.CellWidthResolved);
      }
   }
}

private void Grid_OnFieldPositionChanged(object sender, FieldPositionChangedEventArgs e)
{
   if (grid.FieldLayouts[0].Fields.Contains(e.Field))
   {
      foreach (var field in grid.FieldLayouts[0].Fields)
      {
         if (field.Index < grid.FieldLayouts[1].Fields.Count)
         {
            var field2 = grid.FieldLayouts[1].Fields[field.Index];
            field2.ActualPosition = new FieldPosition(field.ActualPosition.Column,
                        field.ActualPosition.Row,
                        field.ActualPosition.ColumnSpan,
                        field.ActualPosition.RowSpan);
         }
      }
   }
}

Note: I’m using the two methods I originally defined which expect two field layout objects only, feel free to substitute them for the more generic ones I showed in a previous post

Now the problem we had previously with this self-referencing view model is that XamDataGrid matches to the first field layout everytime, we’re going to programmatically change this. As you can see from the XAML, the second field layout hides the LabelLocation, so what we want is that when rendering the child nodes, we use the second field layout and obviously when rendering the parent, we want the first field layout. So let’s assign keys to both field layouts.

I’ve given the key “parent” to the first field layout and “child” to the second, i.e.

<igDP:FieldLayout Key="parent">
   <!--- removed for brevity -->
</igDP:FieldLayout>

<igDP:FieldLayout Key="child">
   <!--- removed for brevity -->
</igDP:FieldLayout> 

Now in the code behind (assuming the XamDataGrid has the x:Name “grid”) we can simply add one line to the constructor of the Window hosting the XamDataGrid

grid.AssigningFieldLayoutToItem += grid_AssigningFieldLayoutToItem;

and then create the following method

private void grid_AssigningFieldLayoutToItem(object sender, AssigningFieldLayoutToItemEventArgs e)
{
   if (e.Item != null)
   {
      e.FieldLayout = 
           e.ParentExpandableFieldRecord == null ? 
           grid.FieldLayouts["parent"] : 
           grid.FieldLayouts["child"];			
   }
}

So now you’ll notice that child nodes no longer display the header but the parent nodes still do.

If you’ve recreated this code you’ll notice we’re back to the problem we fixed in a previous post, regarding the child columns not in alignment with the parents.

We can fix this quite easily (although all the kudos for this goes to a colleague of mine who solved this a while ago). What we need to do is created a new DataRecordPresenterStyle for the child layout’s field layout settings, thus

<igDP:FieldLayoutSettings 
     LabelLocation="Hidden" 
     DataRecordPresenterStyle="{StaticResource childDataRecordStyle}"/>

and the corresponding childDataRecordStyle will be declared in the resources section as

<controls:ChildDataRecordConverter x:Key="childDataRecordConverter" />

<Style x:Key="childDataRecordStyle" TargetType="{x:Type igDP:DataRecordPresenter}">
   <Setter Property="RenderTransform">
      <Setter.Value>
         <TranslateTransform Y="0" 
               X="{Binding NestingDepth, Converter={StaticResource childDataRecordConverter}}" />
      </Setter.Value>
   </Setter>
</Style>

Finally we need the converter code

public class ChildDataRecordConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      return value == null ? Binding.DoNothing : -(((int) value/2)*17);
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

The trick here is we’re going to transform the rendering of the data record using the nesting depth.

At this point we should now have a view model that looks more natural and columns all lining up, but we still have one problem to solve. The child records need to indent slightly to better show they’re child nodes of a parent node – currently it’s difficult to see (when expanded) whan are child and what are parent nodes. So we’ll look at solving this in the next post.