WPF Icon Overlays

Window code, note that we are binding the Overlay to the ImageSource property of the Counter.

 

<Window x:Class="IMAPChecker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:main="clr-namespace:IMAPChecker"
>
      <Window.TaskbarItemInfo>
        <TaskbarItemInfo 
            Overlay="{Binding ElementName=Counter, Path=ImageSource}" 
            />         
    </Window.TaskbarItemInfo>
    


    <Grid Margin="10">
       …
            <main:CountControl x:Name="Counter"  
                               DisplayCount="{Binding Path=Unseen}"                               
                               HasIssue="{Binding Path=HasError}"
                               IsChecking="{Binding Path=IsChecking}"
                               />

</Grid> </Window>

The counter control Xaml is mainly defining brushes.

<UserControl x:Class="IMAPChecker.CountControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:cc="clr-namespace:IMAPChecker"
             mc:Ignorable="d" Height="16" Width="16">

    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="boolToVisibility"/>

        <RadialGradientBrush  x:Key="EmptyBrush"
                              GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" >
            <GradientStop Color="#a0ffffff" Offset="0" />
            <GradientStop Color="#40ffffff" Offset="0.6"/>
            <GradientStop Color="#40000000" Offset="0.7"/>
            <GradientStop Color="#00000000" Offset="1.25"/>
        </RadialGradientBrush>

        <RadialGradientBrush  x:Key="HighlightBrush"
                              GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" >
            <GradientStop Color="LightGreen" Offset="0" />
            <GradientStop Color="Green" Offset="0.6"/>
            <GradientStop Color="DarkGreen" Offset="0.7"/>
            <GradientStop Color="Green" Offset="1.25"/>
        </RadialGradientBrush>

        <RadialGradientBrush  x:Key="MutedBrush"
                              GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" >
            <GradientStop Color="LightYellow" Offset="0" />
            <GradientStop Color="CornflowerBlue" Offset="0.6"/>
            <GradientStop Color="Blue" Offset="0.7"/>
            <GradientStop Color="Gray" Offset="1.25"/>
        </RadialGradientBrush>

        <RadialGradientBrush  x:Key="CheckingBrush"
                              GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" >
            <GradientStop Color="LightYellow" Offset="0" />
            <GradientStop Color="Gold" Offset="0.6"/>
            <GradientStop Color="GoldenRod" Offset="0.7"/>
            <GradientStop Color="Gold" Offset="1.25"/>
        </RadialGradientBrush>

        <RadialGradientBrush  x:Key="IssueBrush"
                              GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" >
            <GradientStop Color="LightPink" Offset="0" />
            <GradientStop Color="Red" Offset="0.6"/>
            <GradientStop Color="DarkRed" Offset="0.7"/>
            <GradientStop Color="Red" Offset="1.25"/>
        </RadialGradientBrush>
    </UserControl.Resources>
    <Border BorderThickness="1" Name="ColourBorder"
        CornerRadius="5" 
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch"
        Background="{StaticResource CheckingBrush}">

        <Viewbox HorizontalAlignment="Center">
            <TextBlock Name="TextBlock"
                    HorizontalAlignment="Stretch" VerticalAlignment="Center"
                    TextAlignment="Center" TextWrapping="NoWrap" 
                    Foreground="Gray" FontWeight="Bold"  
                    Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cc:CountControl}}, Path=DisplayCount}"
                    />
            <!--Text="1"-->
        </Viewbox>

        <Border.BorderBrush>
            <LinearGradientBrush EndPoint="1,1" StartPoint="0,0">
                <GradientStop Color="LightGray" Offset="0" />
                <GradientStop Color="DarkSlateGray" Offset="1" />
            </LinearGradientBrush>
        </Border.BorderBrush>
    </Border>

</UserControl>

The fun begins in the code behind, first there is state logic mapping the state to brushes, which I could alternatively do via a Convertor but the logic seemed to be part of the control so made sense here

public partial class CountControl : UserControl
 {
     public CountControl()
     {
         InitializeComponent();
         InitializeBitmapGeneration();
         DisplayCount = 40;
     }

     public static readonly DependencyProperty DisplayCountProperty = DependencyProperty.Register(
         "DisplayCount",
         typeof(int),
         typeof(CountControl),
         new UIPropertyMetadata(0,
             (d, e) => ((CountControl)d)._OnDisplayChanged()));

     public static readonly DependencyProperty HasIssueProperty = DependencyProperty.Register(
      "HasIssue",
      typeof(bool),
      typeof(CountControl),
      new UIPropertyMetadata(false,
          (d, e) => ((CountControl)d)._OnDisplayChanged()));

     public static readonly DependencyProperty IsCheckingProperty = DependencyProperty.Register(
   "IsChecking",
   typeof(bool),
   typeof(CountControl),
   new UIPropertyMetadata(false,
       (d, e) => ((CountControl)d)._OnDisplayChanged()));

     public static readonly DependencyProperty HasVolumeProperty = DependencyProperty.Register(
   "HasVolume",
   typeof(bool),
   typeof(CountControl),
   new UIPropertyMetadata(false,
       (d, e) => ((CountControl)d)._OnDisplayChanged()));

     public int DisplayCount
     {
         get { return (int)GetValue(DisplayCountProperty); }
         set { SetValue(DisplayCountProperty, value); }
     }

     public bool HasIssue
     {
         get { return (bool)GetValue(HasIssueProperty); }
         set { SetValue(HasIssueProperty, value); }
     }

     public bool HasVolume
     {
         get { return (bool)GetValue(HasVolumeProperty); }
         set { SetValue(HasVolumeProperty, value); }
     }

     public bool IsChecking
     {
         get { return (bool)GetValue(IsCheckingProperty); }
         set { SetValue(IsCheckingProperty, value); }
     }

     private void _OnDisplayChanged()
     {
         ImageSource = null;
         if (IsChecking)
         {
             ColourBorder.Background = (Brush)Resources["CheckingBrush"];
             TextBlock.Foreground = Brushes.Black;
             return;
         }

         if (HasIssue)
         {
             ColourBorder.Background = (Brush)Resources["IssueBrush"];
             TextBlock.Foreground = Brushes.White;
             return;
         }

         if (HasVolume == false)
         {
             ColourBorder.Background = (Brush)Resources["MutedBrush"];
             TextBlock.Foreground = Brushes.Black;
             return;
         }

         if (DisplayCount == 0)
         {
             ColourBorder.Background = (Brush)Resources["EmptyBrush"];
             TextBlock.Foreground = Brushes.Black;
         }
         else
         {
             ColourBorder.Background = (Brush)Resources["HighlightBrush"];
             TextBlock.Foreground = Brushes.White;
         }


     }

And then we have the fun part where we convert the Control into an image.

   #region Should be in base class

        protected void InitializeBitmapGeneration()
        {
            LayoutUpdated += (sender, e) => _UpdateImageSource();
        }

        public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
           "ImageSource",
           typeof(ImageSource),
           typeof(CountControl),
           new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets the ImageSource property.  This dependency property 
        /// indicates ....
        /// </summary>
        public ImageSource ImageSource
        {
            get { return (ImageSource)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }

        private void _UpdateImageSource()
        {
            if (ActualWidth == 0 || ActualHeight == 0)
            {
                return;
            }
            ImageSource = GenerateBitmapSource(this, 16, 16);
        }

        public static BitmapSource GenerateBitmapSource(ImageSource img)
        {
            return GenerateBitmapSource(img, img.Width, img.Height);
        }

        public static BitmapSource GenerateBitmapSource(ImageSource img, double renderWidth, double renderHeight)
        {
            var dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                dc.DrawImage(img, new Rect(0, 0, renderWidth, renderHeight));
            }
            var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
            bmp.Render(dv);
            return bmp;
        }

        public static BitmapSource GenerateBitmapSource(Visual visual, double renderWidth, double renderHeight)
        {
            var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
            var dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                dc.DrawRectangle(new VisualBrush(visual), null, new Rect(0, 0, renderWidth, renderHeight));
            }
            bmp.Render(dv);
            return bmp;
        }
        #endregion

    }
}
Advertisement

A good nights coding

Everybody has a personal standard. We all like to think it’s pretty good. but sometimes we do a piece of work and we feel that we excel way above those standards. Last night was one of those for me.

I was leaving work until 6:30, and my boss wanted to talk about adding some functionality to allow us to a UI that start/stops individual things, so that it could also start/stop many things. But the UI is currently tree based, so how could this be achieved…

Fortunately I’d based the UI to look very much like Windows Explorer/Control Panel and finally I had a reason to implement search, the box in the top right. This way I could search for a set of processes, and then start/stop all. Even better the UI was shared with a personal project I was working on that wanted context sensitive search too, so at 8pm I rolled my sleeves up, sat down, and everything just worked perfectly.

First I implemented something that was so close to ICommandSource, that when I came across it, it seemed a perfectly natural progression. Later I realised why ICommandSource exists but not all controls use it, so I dropped the interface and kept the intent. I was struggling to correctly watermark the search box until I came across DataTrigger and only one StackOverflow search to find out why it wasn’t working properly.

Suddenly I realised I’d taken a simple restyling of a NavigationWindow into a new control, I’d investigated and learned new features, I’d worked inside an MS framework, and had decided when was best to follow other standards that closely align but not slavishly dictate the framework where it was of no value. I’d even sorted out a nasty bug that I’ve been struggling with for days, just by glimpsing at it. I was on fire. I just need to make sure I can carry on like this to see if I can get my personal standard up even higher.

I’ll follow this up with some posts describing this UI control, but for now you can see my previous post on RedGreenRefactor to see an example of this.

RedGreenRefactor v0.1

I have some ideas about a tool to assist and support Red Green refactor cycles as you follow a TDD loop, and my first iteration towards that is now available. This is incredibly basic right now from where I intend to take it.

Usage

This is the basic process to use RedGreenRefactor right now.

Startup

You need to select a Visual Studio solution to monitor. You can change to another at any time on the Settings page.  RedGreenRefactor will parse the projects (*.csproj) and find all those that use a test framework (only nBehave supported in this release)

rgr1

Define the intent of one or many test cycles

Now go to the test cycles list and add what you think you intend to change, and if you want to group them by release. Start to work on your first cycles.

rgr3

Working on an Intention

Start your TDD cycle, so in VS add a new test. Every time you recompile, RedGreenRefactor will run the tests automatically and record the results. Over time you build up a history of your changes.

rgr3

Home Page

Right now the Home Page tries to give you everything you need and is starting to show a small fragment of the reporting capabilities planned.

rgr4

Download

Download RedGreenRefactor.0.1.123.121.msi

What is the tool for?

Right now, RedGreenRefactor will automatically run your tests every time you re-compile or click Run Now. My original idea was to simply capture these and provide reports back on how you are doing.

I use RedGreenRefactor to help ensure I’ve followed my cycle through failing tests (including having Pending specification steps) and then into Green, and refactor. My plan is to get RedGreenRefactor to help with that and marking the difference between test development (i.e. Red stage) and functional development (i.e. Green and Refactor). However by collecting these test runs, I think many more useful reports can be made available, ranging from estimation assistance (length of time that changes were made including a set of keywords), productivity (number of tests), and personal contribution to coverage are just a few.

In addition I also think that simple things like better check in comments in your VCS of choice can be easily achieved if a tool knows what you have changed. In addition I recognise that there is a relationship between test cycles and bug fixes so integrate with tools such as JIRA may also be relevant.

Future functionality

  • Support more test frameworks e.g. nUnit, mbUnit
  • Detect refactorings and code transformations
  • Detect change to coverage levels
  • Support workflows (e.g. UI only changes may not generate a Red phase)
  • Generate reports
  • Integrate with version control (so we simplify the commit cycle)
  • Integrate with VS
  • Integrate with Bug Trackers

Transformation priority premise

Another of those posts that’s actually a bookmark for myself.

The Transformation Priority Premise by Uncle Bob Martin. http://cleancoder.posterous.com/the-transformation-priority-premise

This really has got me thinking at the moment, in fact I’m wondering if it might be worth doing in association with a “TDD as if you meant it” session (designed by Keith Braithwaite but described here). In this session we can walk the willing victim (I’ll never forget Keith being my conscience Smile) through the minimal TDD but at decribe this in terms of transformations. I think it would be really interesting to take feedback from an audience while the coder is headphoned, or even better working remotely, so they can’t hear what we are describing.

How to fail an interview while being totally accurate

aka Value types vs Reference types

Thanks Eric, I’m never going to get another job.

If you are employed in the C# world, then you’ve been through an interview process. I think I have a better chance of becoming a millionaire by betting everybody that has a C# job £10 that they were asked the difference between value types and reference types as an interview question, than by winning the lottery. It is one of the de-facto questions that you ask as an interviewer and expect to be asked as a candidate. The answer that people want to hear is simple,

Value types go on the stack, Reference types go on the heap.

Except that is wrong according to that man who knows. Don’t believe me, go read The Truth About Value Types.

The dilemma

So here’s the problem, do I tell people what they want to hear or what I now know is correct? Can I interrupt an interview and ask if they read Eric Lippert’s Fabulous adventures in coding, before I answer the next question?

I think from now on, I’m damned. Now I know the truth there is no way I can keep quiet, I’m not that kind of person. Then again, who likes being corrected in an interview?

Thanks Eric, I’m never going to pass another interview. Smile

WPF MeasureOverride and Desired Size

I’ve been struggling to get a custom layout working for an items control due to a large number of Double.Nan being exposed. Finally I found the answer in the MSDN docs (that’ll teach me).

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.measureoverride.aspx

It appears there are three sizes for each WPF framework element.

Height, Width – As defined at design time

ActualHeight, ActualWidth – Where the sizes will end up once the calls to elem.Arrange(…) via ArrangeOverride of the Collection control have completed

and introducing..

DesiredSize.Height, Desized.Width – which is the value that was returned in each UIElements.MeasureOverride(…)

This means that for complex layouts you will need to calculate the entire appearance at Measure time, and then again and Arrange time.

LinqToSQL:Alternative to mocking the Db

One of the really nice things about LinqToSQL is how simple it makes it to produce a new database. It fact it’s so easy you can produce a real DB with less effort than a Mock’d one.

I’m sure this has to be bad in some way, but I’ve no idea what that is yet. I’ll need to try it out on a decent environment with a Build Server (like at home).

public const string UnitTestConnection = “Data Source=.;Initial Catalog=UnitTest;Integrated Security=True”;

MyDataContext context = new MyDataContext(UnitTestConnection);
if (context.DatabaseExists())
{
    context.DeleteDatabase();
}
context.CreateDatabase();
context.SubmitChanges();

Improving my Test driven development

I’ve just put a new system live, that I’ve been developing over the past few weeks. Basically its a document approval system. One set of users fill in a form, more users approve or reject it, finally one team signs it off and takes the document to the next system. Very simple.

I started well and designed a framework that I thought was nicely extensible. I wanted to avoid having to create the backend ever again, and simply plug UI and workflow approval definitions on top.

I decided that the UI would be pointless to test (initially) and so created unit tests for the backend. By using Linq to SQL I discovered that I could create a blank empty database every time I ran the tests as part of an Assembly level setup method, which considerably reduced my mocking needs. Okay it removed them. I built a complete set of unit Tests to cover the interaction as I saw them going through an entire lifecycle of every process I could think of.

Given such a good start, I have to admit that my final result is not impressive. As I moved into the UI layer I stopped running the tests (we don’t use CruiseControl). We discovered that there wasn’t just one big document, but it actually made more sense as two. This required quite a big change to the Engine and Database layers to handle this but unfortunately the unit tests stayed off.

As the application was small it was incredibly easy to test that the new design worked as planned without using the tests. I am used to an automated build / test runner, so I just carried on. Now as I come to run them again I find I can’t remember what the tests were supposed to do

Enter Behaviour Driven Design or BDD. BD seems to be TDD with a new name and a better way of constructing your tests to make them readable. It follows a grammar that allows business types to get involved.

As a <role> I want to <goal> so that <motivation>.

Given <assumption> when <action> then <test>

At this point I’ve only read about it but Scott Bellware’s article  seems to be the best. There also tool support but none of it seems to go from specification to code.

Update: Dan North’s article is better http://dannorth.net/introducing-bdd

Have language features changed the way we work for the better?

Craig Murphy dropped a little coding challenge on his blog the other day. This prompted me to write the responses as below. I’ve tried to target each one towards using a particular technology as the framework has developed.

Have a look and tell me which is your preferred answer, or propose a new one (but again try to target a language feature). I’d love to know who you why you choose that language feature over another.

Option 1. With Linq

private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
 
static void Main(string[] args)
{
    char c = Console.ReadKey().KeyChar;
 
    var myChars = from character in alphabet
                  where character <= c
                  select character;
 
    var fullRow = myChars.Skip(1).Reverse().Concat(myChars);
 
    var myRows = (from character in myChars
                  select ConvertToSpaces(character, fullRow));
 
    var reverseRows = myRows.Reverse().Skip(1);
    myRows = myRows.Concat(reverseRows);
 
    Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
    foreach (string line in myRows)
        Console.WriteLine(line);
 
    Console.ReadKey();
}
 
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
    return new string(
    (from character in characters
     select character == wanted ? character : ' ').ToArray());
}

Option 2. With Generics

 
class Program
  {
      private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
 
      static void Main(string[] args)
      {
          char c = Console.ReadKey().KeyChar;
 
          List<char> myChars = new List<char>();
          foreach (char character in alphabet)
          {
              if (character <= c)
                  myChars.Add(character);
          }
 
          List<char> temp = new List<char>(Reverse<char>(AllButFirst<char>(myChars)));
          temp.AddRange(myChars);
          string fullRow = new string(temp.ToArray());
 
          List<string> myRows = new List<string>();
          foreach (char character in myChars)
          {
              myRows.Add(ConvertToSpaces(character, fullRow));
          }
 
          IEnumerable<string> reverseRows = AllButFirst<string>(Reverse<string>(myRows));
          myRows.AddRange(reverseRows);
 
          Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
          foreach (string line in myRows)
              Console.WriteLine(line);
 
          Console.ReadKey();
      }
 
      private static IEnumerable<T> Reverse<T>(IEnumerable<T> myChars)
      {
          Stack<T> reverse = new Stack<T>();
          foreach (T character in myChars)
          {
              reverse.Push(character);
          }
          while (reverse.Count > 0)
          {
              yield return reverse.Pop();
          }
      }
 
      private static IEnumerable<T> AllButFirst<T>(IEnumerable<T> myChars)
      {
           bool first = true;
          foreach (T character in myChars)
          {
              if (first)
                  first = false;
              else
                  yield return character;
          }
      }
      
 
      private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
      {
          StringBuilder result = new StringBuilder();
          foreach (char character in characters)
          {
              result.Append(character == wanted ? character : ' ');
          }
          return result.ToString();
      }
  }

Option 3. Using IEnumerable

 

class ProgramDNv2
{
    private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
        
    static void Main(string[] args)
    {
        DiamondChars diamond = new DiamondChars();
        diamond.chars = GetChars(     Console.ReadKey().KeyChar);
        foreach (string line in diamond)
        {
            Console.WriteLine(line);
        }
        Console.ReadKey();
    }
 
        private static string GetChars(char MidChar)
        {
            string chars = alphabet.Substring(0, alphabet.IndexOf(MidChar) + 1);
            return chars;
        }
 
    private class DiamondChars : IEnumerable<String>
    {
        public string chars;
 
        #region IEnumerable<string> Members
 
        public IEnumerator<string> GetEnumerator()
        {
            int index = 0;
            foreach (char character in chars)
            {
                yield return MakeLine(character, index);
                index++;
            }
            
            index--;
            foreach (char character in chars.Reverse())
            {
                if (index < chars.Length - 1)
                {
                    yield return MakeLine(character, index);
                }
                index--;
            }
        }
 
        #endregion
 
        private string MakeLine(char character, int index)
        {
            string line = new string(chars[index], 1).PadLeft(chars.Length - index);
 
            if (index > 0)
                 return line + new string(chars[index], 1).PadLeft(index * 2);
            else
                 return line;
        }
 
        #region IEnumerable Members
 
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        #endregion
    }
 
}

Option 4. Simple recursion

 
    class ProgramDNv1
    {
        static void Main(string[] args)
        {
            string input = "abcde";
            StringBuilder result = new StringBuilder();
            BuildDiamond(0, input, result);
            Console.WriteLine(result);
        }
 
 
 
        private static void BuildDiamond(int index, string input, StringBuilder result)
        {
            string line = new string(input[index], 1).PadLeft(input.Length - index);
            string line2 = new string(input[index], 1).PadLeft(index * 2);
            result.Append(line);
            if (index > 0)
                result.Append(line2);
            result.Append(Environment.NewLine);
            if (index < input.Length - 1)
            {
                BuildDiamond(index + 1, input, result);
                result.Append(line);
                if (index > 0)
                    result.Append(line2);
                result.Append(Environment.NewLine);
            }
        }
    }

Now add a quick comment below telling you preferred implementation and briefly why. Thanks.

Providing extensible classes: An alternative to inheritance and events

I have a list that is cached. When I come to refresh the list I don’t want to just throw it away and start again, so I use the following.
private void UpdateChildren(IEnumerable<Guid> fromDb, IEnumerable<Model> cached )
{
    List<Model> unseen = new List<Model>(cached); 
 
    foreach (Model child in cached)
    {
        Guid childID = child.Id;
        if (fromDb.Contains(childID) == false)
            cached.Add(CreateModel(childID));
        //seen it now
        unseen.Remove(child);  
    }
    //Delete missing items
    foreach (Model child in unseen)
    {
        DisposeModel(child);
        cached.Remove(child);
    }
}
 
private void DisposeModel(Model child)
{
    // Maybe do nothing
} 
 
private Model CreateModel(Guid child)
{
    return new Model(child);
} 

This works fine but it isn’t very generic. Let’s make some changes

Creating a class

Currently this isn’t really a class, it could be expressed as three static methods. By including the cached list we can start to provide a reusable class with state.

class CachedCollection
{
    private List<Model> _cached = new List<Model>();
 
    private void UpdateChildren(IEnumerable<Guid> fromDb)
    {
        List<Model> unseen = new List<Model>(_cached); 
 
        foreach (Model child in _cached)

Mapping from Guid to Model

Currently we know how to compare a Guid and a Model, since the model has a property that exposes that Guid again. We cannot be certain that this so the case every time so now we need to go for a more generic pairing. In this case I suggest moving from a List<Model> to a Dictionary<Guid, Model>.

 

private Dictionary<Guid, Model> _known = new Dictionary<Guid, Model>();
public void UpdateItems(IEnumerable<Guid> iEnumerable)
{
    ...
    foreach (Model item in iEnumerable)
    {
        if (_known.ContainsKey(item))

Now our paired relationship is completely external to the classes themselves. This is a common feature of code that has been made reusable, in that the method of relating things is sub optimal, in this case with a memory overhead. The dictionaries key hashing lookup will provide a performance boost whether that is required for this application or not.

Applying Generic types

Not much makes a code more generic than applying Generic types, in this case we can refactor the fixed types, but this is full of issues. In this case lets consider converting the Guid to TActual and the Model to TDesired

private Model CreateModel(Guid child)
{
    return new Model(child);
}

If we look at the CreateModel method we note that this is currently creating a new TDesired from a TActual. We can add a new constraint to the the class defintion, but I don’t know of a way to specify that a Type has a particular constructor that takes a single argument.

//Just gets me a ') expected' error.
class CachedCollection<TActual, TDesired> where TDesired:new(TActual)

I can of course make my class abstract and leave it to the derivation to handle, but that means I need a derived class.

abstract class CachedCollection<TActual, TDesired> 
{
    private List<Model> _cached = new List<Model>();
 
    private void UpdateChildren(IEnumerable<TActual> fromDb)
    {
        List<TDesired> unseen = new List<TDesired>(_cached); 
 
        foreach (TDesired child in _cached)
        {
            TActual childID = child.Id;
            if (fromDb.Contains(childID) == false)
                _cached.Add(CreateModel(childID));
            //seen it now
            unseen.Remove(child);  
        }
        //Delete missing items
        foreach (TDesired child in unseen)
        {
            DisposeModel(child);
            _cached.Remove(child);
        }
    }
 
    private abstract void DisposeModel(TDesired child);
    private abstract TDesired CreateModel(TActual child);
}

Of course when we consider using abstract and virtual methods, we start to consider functions as pieces of code that can be referred to. Before DotNet 2.0 there the only way to do this was to use delegates. Now where these functions are optional you may see them exposed as events. These days we have some alternatives.

Generic delegates

There are three great Generic delegate types available since DotNet 2.0

//http://msdn.microsoft.com/en-us/library/kt456a2y.aspx
public delegate TOutput Converter<TInput, TOutput>(TInput input)
 
//http://msdn.microsoft.com/en-us/library/system.action.aspx
public delegate void Action<T>(T input)
 
//http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx
public delegate bool Predicate<T>(T input)
 
These are great building blocks and along with 3.5’s lambda syntax let us provide functions almost as simply as by deriving a class. For example we can convert
private abstract TDesired CreateModel(TActual child);
public void Update()
{
    ...
    x = CreateModel(...);
    ...
}
Into
private Converter<TActualItem, TAlternateItem> _createAlternateItem 
    = new Converter<TActualItem, TAlternateItem>(
        (TActualItem actual) => {throw new NotImplementedException();}
    );
 
public void Update()
{
    ...
    x = _createAlternateItem (...);
    ...
}

Conclusion

For me, this is very powerful. It means we can take our original example and produce the following non-abstract class.

class CollectionSync<TActualItem, TAlternateItem>
{
    public CollectionSync(Converter<TActualItem, TAlternateItem> createAlternateItem)
    {
        _createAlternateItem = createAlternateItem;
    }
 
    public CollectionSync(Converter<TActualItem, TAlternateItem> createAlternateItem, 
        IEnumerable<TActualItem> list) 
        : this(createAlternateItem)
    {
        foreach (TActualItem actual in list)
        {
            _known.Add(actual, _createAlternateItem(actual));
        }
    }
 
    private Dictionary<TActualItem, TAlternateItem> _known 
        = new Dictionary<TActualItem, TAlternateItem>();
    private Converter<TActualItem, TAlternateItem> _createAlternateItem = null;
    private Action<TAlternateItem> _disposeAlternate 
        = new Action<TAlternateItem>((TAlternateItem alternate) => { });
    private Action<KeyValuePair<TActualItem, TAlternateItem>> _udateSingleAlternate 
        = ((KeyValuePair<TActualItem, TAlternateItem> kvp) => { });
 
    public void UpdateItems(IEnumerable<TActualItem> iEnumerable)
    {
        List<TActualItem> unseen = new List<TActualItem>(_known.Keys);
 
        foreach (TActualItem item in iEnumerable)
        {
            if (_known.ContainsKey(item))
            {
                _udateSingleAlternate(
                    new KeyValuePair<TActualItem, TAlternateItem>
                        (item, _known[item]));
                unseen.Remove(item);
            }
            else
            {
                TAlternateItem newLVI = _createAlternateItem(item);
                _known[item] = newLVI;
            }
        }
        //Delete missing items
        foreach (TActualItem item in unseen)
        {
            _disposeAlternate(_known[item]);
            _known.Remove(item);
        }
    }
}