Wednesday, April 14, 2010
Wednesday, April 14, 2010 2:11:13 PM (GMT Daylight Time, UTC+01:00) (C#)

LINQ to Objects in C# has been around for a while now – and yet I’m regularly amazed at how easy LINQ has made it to perform what would have previously been fairly tedious tasks (well unless you were very clever and had written your own set of IEnumerable helper methods)  - like the following – where I needed to synchronise a list of records in a database…

/// <summary>
/// Let's synchronise some sheep...
/// </summary>
/// <param name="newSheep"></param>
/// <param name="db"></param>
/// <returns></returns>
public IEnumerable<Sheep> SynchronizeSheep(IEnumerable<Sheep> newSheep, IDbService db)
{
    IEnumerable<Sheep> oldSheep = db.GetSheeps();

    foreach (var delete in oldSheep.Except(newSheep))
    {
        db.DeleteSheep(delete.Id);
    }

    foreach (var update in newSheep.Intersect(oldSheep))
    {
        db.UpdateSheep(update);
    }

    foreach (var addition in newSheep.Except(oldSheep))
    {
        db.InsertSheep(addition);
    }

    return db.GetSheeps();
}


| Comments [0] | | #  
Tuesday, September 01, 2009
Tuesday, September 01, 2009 11:09:39 PM (GMT Daylight Time, UTC+01:00) (C# | General | Visual Studio | WPF)

I’m pretty sure that anyone who actually likes to ‘make stuff’ and has been a programmer at least once in their life – has got a short list of pet projects that he/she has started – and maybe even finished :-)

Here are a few of my ‘pets’.

CodeDom class generator for VS2005/2008

addin-screenshot_01This was an early attempt of mine at writing a Visual Studio Add-in - designed to create a class from a database query, table or stored procedure. There’s a ton of stuff like this out there – but I wanted something that generated the class from the DataTable – SchemaTable of an IReader – so that a class could be generated from any query or shape for use with DTOs, reporting, or a simple domain model. You can choose from C#, VB or C++ to generate the class as well as a number of styles of classes – from a built-in IReader constructor, attribute based mapper, or plain old CLR object (POCO). There also doesn’t have to be any data in the result set for this to work since the SchemaTable will be returned regardless.

 addin-screenshot_02

The Add-in also adds an ‘Open Folder’ option to the context menu of all solutions, projects, folders, etc. in Solution Explorer. This feature exists as of VS 2008 – but I wanted it at the top of the context menu – not at the bottom.

You can download the Add-in here at - FiftyEightBitsAddin.zip Just unzip and place the contents of the zip file into any one of the Add-in locations for VS2008.

 

PreCode Code Snippet Plugin for WLW

This is an open source project hosted at Codeplex – a plugin for Windows Live Writer that helps to format code snippets before pasting them into a blog post (or elsewhere). It was written for the excellent SyntaxHighlther from Alex Gorbatchev. It’s a WPF app – and also includes a standalone desktop version for pasting formatted code into any app (ideal for Stack Overflow). Please don’t look at this as a reference WPF app though – it’s more than just a little ‘hacky’. The app that follows is my ‘better’ WPF effort. Visit http://www.codeplex.com/precode for more details, the source code and the installer.

 precode_screenshot

 

Gallery Builder – Desktop and Web

If you follow the Photos link above – you’ll see the results of this application. Yet another gallery builder app – however I’ve spent a bit of time on this one – choosing a specific architecture that I think represents a good balance between desktop and web server processing for small to medium size collections of photos. I’ll be hosting a Wiki soon with docs and the full download including the HttpModule that is used display galleries online (along with a sample app and extensibility features). The module can be integrated into any site and includes full Atom and Rss syndication support, nested galleries, as well as good caching/304 response support.

 0.9.8.1000

A pre-release version of the desktop application can be downloaded from the link below (although it’s not a whole lot of good without the web component). Hand rolling a complete set of control templates for a custom theme in WPF was a great way to get to know the inside of WPF.

NOTE: If there are no other WPF apps on your machine – and this application is the first WPF application you start – the ‘cold’ loading time for a WPF app is very long. Subsequent application loading times are what you’d expect.

GalleryBuilder_0.9.9.1000.zip

 

Yet another Task Management App - DotNetTime

dnt_screenshot

Yet another task/project list manager; only I actually use this one. This is an ASP.Net Model View Presenter application (and hopefully my last Webforms app). I use this to track my own time working on projects or just to ‘monitor’ my own time in general. Implementing multi-language support was a good learning exercise – and until recently this had been my ‘workbench’ throw anything at it hobby app. Now that charting controls are available free from Microsoft – I’ll be adding some charts to the reporting page. Feel free to register and have a play – it’s very basic – but it does what I need. Be gentle too if you’re into web hackery– this was built before my formal introduction to the world of application security and so I wouldn’t be surprised at all if there were XSS or CSRF vulnerabilities (although there shouldn’t be any SQL injection weaknesses – he says).

http://www.58bits.com/dnt



| Comments [0] | | #  
Sunday, August 02, 2009
Sunday, August 02, 2009 2:24:20 AM (GMT Daylight Time, UTC+01:00) (C# | Utilities)

Thanks to this post at .Net Dojo, here’s a utility method for getting a safe value from an XElement, returning a default value if the element was not found.

public static T GetElementValue<T>(XElement parent, string elementId, T defaultValue) where T : IConvertible
{
    XElement element = parent.Element(elementId);
    if (element != null)           
        return (T)Convert.ChangeType(element.Value, typeof(T), CultureInfo.InvariantCulture);           
    else
        return defaultValue;   
}    

I’ve been using this combined with .Net 3.0 object initializers to re-hydrate objects from Xml with safe values, like…

var myClass = new MyClass() 
{ 
    Name = GetElementValue(parent, "Name", String.Empty),
    IsDefault = GetElementValue(parent, "IsDefault ", true),
    YearsLeft = GetElementValue(parent, "Yearsleft", 100)
}


| Comments [0] | | #  
Sunday, July 26, 2009
Sunday, July 26, 2009 7:35:50 AM (GMT Daylight Time, UTC+01:00) (ASP.Net | C#)

Earlier I posted about a compression filter for ASP.NET MVC that was the product of two other posts on compression and QValues. I’ve also seen a couple of posts describing different approaches to creating syndication content via ASP.NET MVC – RSS or Atom feeds. Here are two suggestions – one at DeveloperZen and the other at Stack Overflow that both use an RssActionResult subclass of ActionResult.

What was missing was a 304 Not Modified filter – so that feeds that have not changed can return a 304 Not Modified HTTP Response - saving bandwidth and improving performance of the consumer.

Here’s my attempt at putting it all together using a custom NotModifiedFilter, the CompressionFilter and a SyndicationActionResult class.

First the NotModifiedFilter. This article at the Embarcadero Developer Network was very helpful (along with the W3C standard for 304 Not Modified).

Here’s the filter.

public class NotModifiedFilterAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var response = filterContext.HttpContext.Response;
        var request = filterContext.HttpContext.Request;           

        if ((IsSourceModified(request, response) == false))
        {
            response.SuppressContent = true;
            response.StatusCode = 304;
            response.StatusDescription = "Not Modified";
            // Explicitly set the Content-Length header so the client doesn't wait for
            // content but keeps the connection open for other requests
            response.AddHeader("Content-Length", "0");
        }
    }
}

And here’s the helper method that tests for modified content.

private static bool IsSourceModified(HttpRequestBase request, HttpResponseBase response)
{                  
    bool dateModified = false;
    bool eTagModified = false;

    string requestETagHeader = request.Headers["If-None-Match"] ?? string.Empty;
    string requestIfModifiedSinceHeader = request.Headers["If-Modified-Since"] ?? string.Empty;            
    DateTime requestIfModifiedSince;                    
    DateTime.TryParse(requestIfModifiedSinceHeader, out requestIfModifiedSince);
    
    string responseETagHeader = response.Headers["ETag"] ?? string.Empty;
    string responseLastModifiedHeader = response.Headers["Last-Modified"] ?? string.Empty;
    DateTime responseLastModified;
    DateTime.TryParse(responseLastModifiedHeader, out responseLastModified);

    if (requestIfModifiedSince != DateTime.MinValue && responseLastModified != DateTime.MinValue)
    {
        if (responseLastModified > requestIfModifiedSince)
        {
            TimeSpan diff = responseLastModified - requestIfModifiedSince;
            if (diff > TimeSpan.FromSeconds(1))
            {
                dateModified = true;
            }
        }
    }
    else
    {
        dateModified = true;
    }

    //Leave the default for eTagModified = false so that if we
    //don't get an ETag from the server we will rely on the fileDateModified only           
    if (String.IsNullOrEmpty(responseETagHeader) == false)
    {
        eTagModified = responseETagHeader.Equals(requestETagHeader, StringComparison.Ordinal) == false;
    }

    return (dateModified || eTagModified);    
}

And lastly – here’s my SyndicationActionResult class which uses a Func<FeedData> delegate to get the feed data – and so can be used for any type of feed – Rss, Atom, Sitemaps etc. (FeedData contains the feed content as well as the last modified date and the ETag). Not sure if I’m guilty of cargo cult programming here since I was a little unsure about setting the ‘Last-Modified’ header manually instead of using response.Cache.SetLastModified() method. However the latter was not showing up in the HttpContext of the OnResultExecuted method in the filter. Maybe the runtime moves this value into the headers collection later in the pipeline.

public class SyndicationActionResult : ActionResult
{
    public Func<FeedData> ActionDelegate { get; set; }
    
    public override void ExecuteResult(ControllerContext context)
    {
        if (ActionDelegate != null)
        {
            var response = context.HttpContext.Response;
            var data = ActionDelegate.Invoke() as FeedData;
            if (data != null)
            {
                response.ContentType = data.ContentType;
                response.AppendHeader("Cache-Control", "private");
                response.AppendHeader("Last-Modified", data.LastModifiedDate.ToString("r"));
                //response.Cache.SetLastModified(data.LastModifiedDate);
                response.AppendHeader("ETag", String.Format("\"{0}\"", data.ETag));
                response.Output.WriteLine(data.Content);
                response.StatusCode = 200;
                response.StatusDescription = "OK";
            }
        }
    }
}

Note that we write the content to the response.Output stream - however if the NotModifiedFilter tells us nothing has changed – then this will be suppressed – (although it is important that the ETag remains).

And very lastly - here's the Action in my SyndicationController class that puts it all together, and in this case – is used to provide the aggregate Atom feed on my home page at http://www.58bits.com.

[AcceptVerbs(HttpVerbs.Get)]
[NotModifiedFilter(Order = 1)]
[CompressFilter(Order = 2)]
public SyndicationActionResult SiteFeedAtom()
{
    return new SyndicationActionResult() { ActionDelegate = SyndicationHelper.GetAggregateAtomFeed };
}

As Scott sometimes says -  it may be  “poo”… or it maybe useful. At least it seems to be working ok for me, although suggestions on how any of it might be improved would be greatly appreciated.



| Comments [8] | | #  
Thursday, June 25, 2009
Thursday, June 25, 2009 7:17:09 AM (GMT Daylight Time, UTC+01:00) (C# | WPF)

Charles Petzold’s book, Applications = Code + Markup - received some critical press for not being very pretty. And it’s true that there’s a lot of text and code listings but (and as you’ll see below), he was methodical.

I recently wanted to upgrade a Windows Live Writer plug-in I’d written to use the Windows Presentation Framework (WPF) – instead of WinForms and a custom UI library.

However my first attempt to compile the application as a Class Library resulted in the following error…

“Library project file cannot specify ApplicationDefinition element”.

Thankfully I’d remembered the opening chapters of Charles’ book where he spent considerable time explaining the creation of the application class and initial window. The trick in this case is to remove the App.xaml file. You then need to create your own start-up class – like Program.cs – as shown below, and the application will compile fine as either a Windows Application or Class Library. In the example below extra parameters are passed to the constructor of the main window which is opened as a Dialog – and then checked for the DialogResult value when the window is closed.

public class Program : Application
{
    [STAThread]
    public static void Main()
    {
        var app = new Program();
        app.Run();
    }

    protected override void OnStartup(StartupEventArgs args)
    {
        base.OnStartup(args);

        var window = new PreCodeWindow(new PreCodeSettings(), PreCodeWindow.Mode.StandAlone);
        window.ShowDialog();
        if (window.DialogResult.HasValue && window.DialogResult.Value)
        {
            System.Diagnostics.Debug.WriteLine("OK");
            Clipboard.SetText(window.Code);
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("Not OK");
        }        
    }
}

The downside to this approach is that you no longer have an application level location for placing resource dictionaries and other shared objects - and so these will need to be placed in each window as required.



| Comments [1] | | #  
Saturday, May 02, 2009
Saturday, May 02, 2009 10:17:21 PM (GMT Daylight Time, UTC+01:00) (ASP.Net | C#)

I’d previously created a compression processor for dynamic content – using this excellent post for QValues by Dave Transom. Also just just discovered this post on creating an action filter for compression by Kazi Manzur Rashid.

So combining the two and we have:

public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        // load encodings from header
        QValueList encodings = new QValueList(request.Headers["Accept-Encoding"]);

        // get the types we can handle, can be accepted and in the defined client preference
        QValue preferred = encodings.FindPreferred("gzip", "deflate", "identity");

        // if none of the preferred values were found, but the
        // client can accept wildcard encodings, we'll default
        // to Gzip.
        if (preferred.IsEmpty && encodings.AcceptWildcard && encodings.Find("gzip").IsEmpty)

            preferred = new QValue("gzip");

        HttpResponseBase response = filterContext.HttpContext.Response;
        // handle the preferred encoding
        switch (preferred.Name)
        {
            case "gzip":
                response.AppendHeader("Content-encoding", "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                break;

            case "deflate":
                response.AppendHeader("Content-encoding", "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                break;

            case "identity":
                break;
            default:
                break;
        }
    }
}

Which when applied as below to any action method will enable compression if it’s supported by the browser.

[AcceptVerbs(HttpVerbs.Get)]
[CompressFilter]
public ContentResult SiteMap()
{
    return new ContentResult
               {
                   Content = SyndicationHelper.GetAggregateSiteMap(),
                   ContentType = "application/xml; charset=UTF-8"
               };
}

Download here: QValueAndCompressionFilter.zip



| Comments [7] | | #  
Monday, March 30, 2009
Monday, March 30, 2009 6:45:22 AM (GMT Daylight Time, UTC+01:00) (C# | Utilities)

Alex Gorbatchev has done a great job with version 2.0 of his excellent JavaScript SyntaxHighlighter. And I’ve just updated my code snippet plugin for Windows Live Writer – with SyntaxHighlighter 2.0 support, as well as a new desktop application – useful for pasting code snippets into other apps.. like stackoverflow.com (CTRL-A to select all – and then >> to indent four spaces before pasting into stackoverflow).

The updated plugin is at http://www.codeplex.com/precode

precodeplugin



| Comments [0] | | #  
Sunday, March 22, 2009
Sunday, March 22, 2009 2:04:35 AM (GMT Standard Time, UTC+00:00) (C#)

I decided to create an aggregate sitemap.xml for the root of my domain. There are sitemap handlers in the blog, otherblog and photo subdirectories already – but I wanted a single sitemap.xml in the root that I could submit to Google.

I started with some pretty hacky attempts... fumbling my way around Linq to Xml. Also came unstuck with namespace normalization – since the sitemap handler in dasBlog is using the older 0.84 version namespace from sitemap.org.  So what I thought would take 20 minutes – ended up taking a bit longer, although the results were worth it since the same approach could be used for aggregating Atom or RSS feeds.

(Note – big thanks to Martin Honnen over at http://social.msdn.microsoft.com/Forums/en-US/categories/ for helping out with some of the Linq to Xml).

The ChangeNamespace helper method does not convert attributes although that could be added as well.

The safe method for loading urls along with the use of an iterator block (yield return) makes the GetElements helper method pretty efficient I think. What’s more, since this returns an IEnumerable<XElement> – additional Linq query expressions could be used here – like sorting or grouping; particularly useful if you were aggregating an Atom feed and wanted to sort by date.

static void Main(string[] args)
{
    XDocument feed = MergeSiteMaps(new List<string>() { "http://www.58bits.com/blog/googleSitemap.ashx", "http://www.58bits.com/otherblog/googleSiteMap.ashx",  "http://www.58bits.com/photos/sitemap.xml"});

    XNamespace sm = "http://www.sitemaps.org/schemas/sitemap/0.9";

    foreach (XElement location in feed.Root.Elements(sm + "url").Elements(sm + "loc")) 
    {
        Console.WriteLine((string)location); 
    } 
}

public static XDocument MergeSiteMaps(IEnumerable<string> urls)
{
    XNamespace sm = "http://www.sitemaps.org/schemas/sitemap/0.9";
    XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
    XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
    string schemaLocation = "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd";

    //Our container sitemap document
    return new XDocument(
        new XDeclaration("1.0", "utf-8", "yes"),
        new XElement(sm + "urlset",
            new XAttribute(XNamespace.Xmlns + "xsi", xsi),
            new XAttribute(XNamespace.Xmlns + "xsd", xsd),
            new XAttribute(xsi + "schemaLocation", schemaLocation),

            new XElement(sm + "url",
                new XElement(sm + "loc", "http://www.58bits.com/"),
                new XElement(sm + "lastmod", DateTime.Now.ToString("yyyy-MM-dd")),
                new XElement(sm + "changefreq", "monthly"),
                new XElement(sm + "priority", "1.0")),

            new XElement(sm + "url",
               new XElement(sm + "loc", "http://www.58bits.com/default.aspx"),
               new XElement(sm + "lastmod", DateTime.Now.ToString("yyyy-MM-dd")),
               new XElement(sm + "changefreq", "monthly"),
               new XElement(sm + "priority", "1.0")),

            GetElements(sm, urls, "url"))
        );
}

private static IEnumerable<XElement> GetElements(XNamespace ns, IEnumerable<string> urls, string elementLocalName)
{
    XElement source;

    foreach (string url in urls)
    {
        try
        {
            source = XElement.Load(url);
        }
        catch (Exception ex)
        {
            //TODO: Log the Url that failed
            string message = ex.Message;
            continue;
        }

        XNamespace defaultNamespace = source.GetDefaultNamespace();
        bool differentNamespace = (ns != defaultNamespace);
        foreach (XElement element in source.Elements(defaultNamespace + elementLocalName))
        {
            if (differentNamespace)
                ChangeNamespace(ns, element);
            yield return element;
        }
    }
}

private static void ChangeNamespace(XNamespace ns, XElement entry)
{
    foreach (XElement e in entry.DescendantsAndSelf())
    {
        if (e.Name.Namespace != XNamespace.None)
        {
            e.Name = ns.GetName(e.Name.LocalName);
        }
    }
}


| Comments [0] | | #  
Wednesday, July 16, 2008
Wednesday, July 16, 2008 2:31:47 PM (GMT Daylight Time, UTC+01:00) (C# | Visual Studio)

Yet another tool I've been late coming to - JetBrains ReSharper.

While working though Link in Action I was experimenting with ReSharper 4.0. So cool and extremely helpful when looking at delegates and lambdas.

Here's a delegate assignment..

Predicate<DateTime> isMinimum = delegate(DateTime input) { return (input == DateTime.MinValue); };

And here's the equivalent as a lambda..

Predicate<DateTime> isMinimum = input => (input == DateTime.MinValue);

And here's the ReSharper magic that converts from lambdas to delegates and back again...

resharper4



| Comments [0] | | #  
Thursday, July 03, 2008
Thursday, July 03, 2008 7:05:17 PM (GMT Daylight Time, UTC+01:00) (C# | Utilities)

Thanks to Alexander Groß for pointing me to syntaxhighlighter.  I still think Leo Vildosola's Code Snippet plugin and highlighter for Windows Live Writer is amazing. They're both good choices - but I thought I'd give syntaxhighlighter a try. It produces less markup than Leo's plugin, although it is dependant on a JavaScript lib on the site for the actual highlighting.

PreCodePlugin_Full_2.0.2 The only challenge in using syntaxhighlighter- is that unlike Leo's all-in-one solution - you need to work out a way to format and encode your snippets first, placing them in either a <pre> or <textarea> element. There are a couple of plugins out there that do this - but I wasn't thrilled with the results, and I've wanted to take a quick look at the WLW plugin API for a while now. Seems like everyone is having a go at this - including Rick Strahl.  So here is my attempt - a code snippet plugin for Windows Live Writer...

Scott also directed me to the Past As plugin on Codeplex - which I'll be trying out as well.

The result - using my plugin - and syntaxhighlighter on the site...

 

public override void CleanUp()
{
    //Remve the Async event listener
    AsyncTaskManager.ItemProcessComplete -= AsyncTaskManager_PreviewItemProcessed;
    this.Logger = null;
}
:-)


| Comments [0] | | #  
Monday, June 30, 2008
Monday, June 30, 2008 8:27:13 PM (GMT Daylight Time, UTC+01:00) (C#)

Using an enumeration to display a list of values in the user interface (UI) has obvious limitations. You'll be limited to the rules of enumeration values - no spaces, multi-words etc. You won't be able to offer localized versions of the strings used to describe each enumeration value. And you'll have to hard code and parse all possible values in order to present a list of values in a UI element.

Here's an article on five great patterns that can be used to create "look-up" or "reference" types (reference type in this case meaning a data structure that is used to represent a list of possible values that another type will depend on - like High, Medium, Low, or Fast and Slow).

Below is the code I used recently to create a type based on the descriptor pattern; a  reference type that will be used to assign a JobStatus to a Job class. What I like about this approach, is that with correct == and != operator overloads - it's a 1:1 swap with an existing enumeration type - so no code changes are required where an enumeration type may have been used initially.

The weakness of this pattern is that like enumerations - the class has to be coded - and so if the list of values changes the code will need to change too. That said, for small to medium size lists of "look-up" values (combined with a little code generation) this is a great way to offer type safe values as well as a UI and culture friendly list.

The ToString() override and the IList<JobStatius> GetValues() method make this type databinding friendly too.

public sealed class JobStatus
{
    //Private constructor - only our static properties are allowed to create instances
    private JobStatus(int value, string name)
    {
        _value = value;
        _name = String.Copy(name);
    }
    
    //Readonly Value property
    private int _value;
    public int Value { get { return _value; } }

    //Readonly Name property
    private string _name;
    public string Name { get { return _name; }}

    private static JobStatus _waiting = new JobStatus(1, "Waiting");
    public static JobStatus Waiting
    {
        get { return _waiting; }
    }

    private static JobStatus _notRun = new JobStatus(2, "Not Run");
    public static JobStatus NotRun
    {
        get { return _notRun; }
    }

    private static JobStatus _active = new JobStatus(3, "Active");
    public static JobStatus Active
    {
        get { return _active; }
    }

    private static JobStatus _completed = new JobStatus(4, "Completed");
    public static JobStatus Completed
    {
        get { return _completed; }
    }

    private static JobStatus _cancelled = new JobStatus(5, "Cancelled");
    public static JobStatus Cancelled
    {
        get { return _cancelled; }
    }

    private static JobStatus _failed = new JobStatus(6, "Failed");
    public static JobStatus Failed
    {
        get { return _failed; }
    }

    public override string ToString()
    {
        return _name;
    }
    
    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        if (GetType() != obj.GetType())
            return false;

        JobStatus status = (JobStatus)obj;

        if (_value != status.Value)
            return false;

        return _value == status.Value;
    }     

    public static bool operator ==(JobStatus status1, JobStatus status2)
    {
        return Object.Equals(status1, status2);
    }

    public static bool operator !=(JobStatus status1, JobStatus status2)
    {
        return !Object.Equals(status1, status2);
    }

    public static IList<JobStatus> GetValues()
    {
        List<JobStatus> values = new List<JobStatus>();

        foreach (PropertyInfo pi in typeof(JobStatus).GetProperties())
        {
            if (pi.PropertyType.Name.Equals("JobStatus", StringComparison.Ordinal))
            {
                values.Add((JobStatus)pi.GetValue(null, null));
            }
        }

        return values;
    }
}


| Comments [0] | | #  
Saturday, June 14, 2008
Saturday, June 14, 2008 3:16:05 PM (GMT Daylight Time, UTC+01:00) (C# | Utilities)

I know Jeff Atwood is a fan of this, and I'm surprised it's not made it on to Scott Hanselman's 2007 Ultimate Developer and Power Users Tool List for Windows tools list yet.

RegexBuddy is a brilliant tool and a great way to learn regular expressions. The documentation and introduction to regex is worth the price of admission alone.

regexbuddy
  (click to enlarge)

The expression tree view in the lower window practically talks to you as you build up and test your expressions. The expression to the right will match any incoming Url to myabsolutepath/subdir that begins and ends with either:

myabsolutepath/subdir
myabsolutepath/subdir/

or

myabsolutepath/subdir/*.aspx
myabsolutepath/subdir/*.ashx

I love this application.



| Comments [0] | | #  
Saturday, June 07, 2008
Saturday, June 07, 2008 6:35:26 PM (GMT Daylight Time, UTC+01:00) (C#)

I needed an undo stack today - but wanted it to behave like a queue when it was full, dropping the oldest items in the collection to make room for new ones. Found two posts - Undo Functionality with a Limited Stack, and also a reference to an identically named collection called LimitedStack here. 

Was initially thinking of simply writing a wrapper over an array of objects, shifting items along as new ones were added, but using a linked list is a clever solution, as it provides the queue like behavior needed without out any extra code via RemoveFirst() and RemoveLast().

using System;
using System.Collections.Generic;

namespace DotBits.Gallery.Builder.Objects
{
    [Serializable()]
    public class UndoStack<T> : LinkedList<T>
    {
        private int _maxItems;

        public int MaxItems
        {
            get 
            {
               return _maxItems; 
            }
            set
            {
                while (this.Count > value)
                {
                    this.RemoveFirst();
                }
                
                _maxItems = value;
            }
        }

        public UndoStack(int max)
        {
            _maxItems = max;
        }

        public T Peek()
        {
            return this.Last.Value;
        }

        public T Pop()
        {
            LinkedListNode<T> node = this.Last;
            this.RemoveLast();
            return node.Value;
        }

        public void Push(T value)
        {
            LinkedListNode<T> node = new LinkedListNode<T>(value);
            this.AddLast(node);

            if (this.Count > _maxItems)
            {
                this.RemoveFirst();
            }
        }
    }
}



| Comments [0] | | #  
Monday, May 07, 2007
Monday, May 07, 2007 12:54:30 PM (GMT Daylight Time, UTC+01:00) (C#)

Back in March I went to the MSDN Roadshow in London to see presentations on several topics - one of them was LINQ.

In my attempts to keep up with the avalanche of software coming out of Microsoft - I have a short list of beefy books to read, weblogs to keep up with, and videos and Webcasts to watch.

The presentation at the roadshow in March was ok - but I thought for a while about the cost of attending; the time it took to get there - the structured format of the show and my never ending need for utilitarian sources of good information.

Today I came across Mike Champion's very helpful post...

Accelerating Evolution: LINQ News from Mix 2007 which includes a link to a video of Anders' presentation at Mix 2007 .

Anders' presentation is brilliant; fluid and clear - and really demonstrates the LINQ language enhancements well.

What's more I was able to watch it at a time of my choosing, and at my own pace - which makes me wonder a little about the real benefit of the Roadshows (apart from the less than subtle injection of a lot of MS Office 2007 mini-marketing presentations between each of the main items of the event).

Mix 07 on the other hand is a 'whole-n-other' thing.... :-)



| Comments [0] | | #  

search

categories

on this page

ads

archive

Total Posts: 97
This Year: 3
This Month: 0
This Week: 0
Comments: 92