Sunday 21 July 2013

Cartesian Product code sample, LINQ, C#

Starting point
StackOverflow: Cartesian Product + N x M Dynamic Array

Credit: Eric Lippert

Sample code (C#, console app)

namespace CartesianStudy
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public static class Program
    {
        public static void Main()
        {
            var persons = new[]
                {
                    "Peter", 
                    "Mary", 
                    "Ivan", 
                    "Oscar", 
                    "Lucy"
                };

            var flyingDays = new List<string>
                {
                    "Tue", 
                    "Wed", 
                    "Fri", 
                };

            var flights = new List<Flight>
                {
                    new Flight("Air Canada", "AC1152"), 
                    new Flight("CanJet", "C6785"), 
                    new Flight("WestJet", "WS4040"),
                    new Flight("SunWing", "WG423"),
                    new Flight("Air Canada", "AC093"),
                    new Flight("American Airlines", "AA8118"),
                };

            var allCombinations = new IEnumerable<object>[]
                    {
                        persons, flyingDays, flights
                    }.CartesianProduct().ToList();

            foreach (var combination in allCombinations
                .Select(c => c.ToList()))
            {
                Console.WriteLine(
                    "{0} on {1} by {2}", 
                    combination[0], 
                    combination[1], 
                    combination[2]);
            }

            Console.WriteLine(
                "\nCount: {0}\nAny key...", 
                allCombinations.Count);
            
            Console.ReadKey();
        }

        private static IEnumerable<IEnumerable<T>> 
            CartesianProduct<T>(
            this IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct = new[]
                {
                    Enumerable.Empty<T>()
                };

            return sequences.Aggregate(
                emptyProduct,
                (accumulator, sequence) =>
                from accseq in accumulator
                from item in sequence
                select accseq.Concat(new[] { item }));
        }
    }

    public class Flight
    {
        public string Company { get; set; }

        public string Number { get; set; }

        public Flight(string company, string number)
        {
            this.Company = company;
            this.Number = number;
        }

        public override string ToString()
        {
            return string.Format(
                "{0} - {1}", 
                this.Company, 
                this.Number);
        }
    }
}

Friday 15 March 2013

Subclassing SqlDataSource control in ASP.NET application

Scenario: in ASP.NET application, in run-time force all SqlDataSource instances connecting to a specified data source.

The basic usage of SqlDataSource control assumes assigning values to ConnectionString and ProviderName in HTML part of Web Form or Web User Control.

<asp:SqlDataSource ID="Source1" runat="server" ConnectionString="<%? ConnectionString:MyDataSource %" ProviderName="<%$ ConnectionStrings:MyDataSource.ProviderName %>" SelectCommand="..." />

Both values can also be assigned in the code-behind.

In my case, user selects a data source on start of the web application, and may switch to another available data source during the session. Following a data source selection all SqlDataSource instances must use this and only this data source. The connection string is stored in session variable "ActiveDbConnection".

This scenario can be quickly realized by subclassing the SqlDataSource control.

Apparently you cannot subclass it from Web User Control because the latter must inherit from System.Web.UI.UserControl, and thus cannot inherit from SqlDataSource.

But you can create ASP.NET Server Control and then change its superclass from WebControl to SqlDataSource. Following that replace the default constructor. Зresuming the class name is CustomSqlDataSource the replacement be the following one


public CustomSqlDataSource()
{
      ConnectionString =
            HttpContext.Current
                  .Session["ActiveDbConnection"];
      
      ProviderName = "System.Data.OleDb";
}

In HTML part all asp:SqlDataSource tags need to be replaced with asp:CustomSqlDataSource, and the namespace for the class to be registered. And also -- this is very important -- all ConnectionString and ProviderName attributes are to be removed. Otherwise the default constructor we just added will not be called.

<asp:CustomSqlDataSource ID="Source1" runat="server" SelectCommand="..." />

Friday 1 March 2013

Clearing filter in gridview when adding new record

Otherwise a new record may immediately become hidden from user. And the user will most likely add another one, and then one more, again and again.

The developer is rarely capable of seeing an application with user's eyes. An hour of data entry each month could benefit one.

Tuesday 19 February 2013

Handling shortcuts in WPF application

This is a sketchy post, to be completed or discarded later on. The objectives was having inheritance and minimizing the instantiation code.

This is the base class.


public class KeyShortcutBase
{
    private readonly RoutedCommand _command;

    private readonly CommandBinding _commandBinding;

    protected KeyShortcutBase()
    {
        this._command = new RoutedCommand();

        this._commandBinding = new CommandBinding(
            this._command,
            OnExecuted,
            OnCanExecute);
    }

    public void ConnectShortcut(
        UIElement host, InputGesture gesture)
    {
        this.ConnectShortcut(host, new[] { gesture });
    }

    public void ConnectShortcut(
        UIElement host, IEnumerable<InputGesture> gestures)
    {
        foreach (var gesture in gestures)
        {
            this._command.InputGestures.Add(gesture);
        }

        if (host != null)
        {
            host.CommandBindings.Add(this._commandBinding);
        }
    }

    protected virtual void OnCanExecute(
        object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = false;
    }

    protected virtual void OnExecuted(
        object sender, ExecutedRoutedEventArgs e)
    {
    }
}

This is an extension class allowing shorter calls.

public static class KeyShortcutExtender
{
    public static void ConnectShortcut(
        this UIElement host, 
        KeyShortcutBase shortcut, 
        IEnumerable<InputGesture> gestures)
    {
        shortcut.ConnectShortcut(host, gestures);
    }

    public static void ConnectShortcut(
        this UIElement host, 
        KeyShortcutBase shortcut, 
        InputGesture gesture)
    {
        shortcut.ConnectShortcut(host, gesture);
    }
}

This is a subclass.

public class FindItemShortcut : KeyShortcutBase
{
    protected override void OnCanExecute(
        object sender,
        CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    protected override void OnExecuted(
        object sender,
        ExecutedRoutedEventArgs e)
    {
        MessageBox.Show(this.GetType().ToString());
    }
}

The subclass is instantiated in WPF Window with a single shortcut.

this.ConnectShortcut(
    new FindItemShortcut(), 
    new KeyGesture(Key.F, (ModifierKeys)6));

... and with multiple shortcuts.

this.ConnectShortcut(
    new FindItemShortcut(), 
    new InputGesture[]
        {
            new KeyGesture(Key.F, (ModifierKeys)6), 
            new KeyGesture(Key.S, ModifierKeys.Control), 
            new MouseGesture(MouseAction.RightDoubleClick)
        });

So far so good...


Tuesday 12 February 2013

Allowing only single instance of WPF application per login session

The intention is preventing user from starting multiple instances of the same application. Repeated run should activate (restore) the application's main window.

Having this task already resolved for Visual FoxPro through using semaphores, I chose same approach for WPF. Using direct calls to Semaphore API functions in .NET makes rather little sense, since the Semaphore Class provides all required functionality.

First step is removing StartupUri in App.xaml and overriding Application.OnStartup method. This allows instantiating application's main window only after checking that no other instances are running.


namespace WpfApplicationRunOnce
{
    using System.Windows;

    public partial class App
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            if (!AppLauncher.RunApp())
            {
                this.Shutdown(0);
            }
        }
    }
}

Static AppLauncher class either creates instance of the main window or activates the one that already exists.

namespace WpfApplicationRunOnce
{
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Threading;

    public static class AppLauncher
    {
        private const string ApplicationId = "MyAppUniqueId";

        private static MainWindow mainWindow;

        internal enum RegisterResult
        {
            Success,
            AlreadyRunning,
            Failed
        }

        private enum ShowWindowMode
        {
            Maximize = 3,
            Restore = 9
        }

        private enum WindowStyles
        {
            Maximize = 0x01000000
        }

        public static bool RunApp()
        {
            var result = RegisterApp(ApplicationId);

            switch (result)
            {
                case RegisterResult.Success:
                    mainWindow = new MainWindow();
                    mainWindow.Show();
                    return true;

                case RegisterResult.AlreadyRunning:
                    ActivateAppMainWindow();
                    break;

                case RegisterResult.Failed:
                    break;
            }

            return false;
        }

        private static RegisterResult RegisterApp(string appId)
        {
            try
            {
                Semaphore.OpenExisting(appId);
                return RegisterResult.AlreadyRunning;
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                try
                {
                    var semaphore = new Semaphore(1, 1, appId);
                    return RegisterResult.Success;
                }
                catch
                {
                    return RegisterResult.Failed;
                }
            }
        }

        private static void ActivateAppMainWindow()
        {
            var current = Process.GetCurrentProcess();

            var running = Process.GetProcesses()
                .FirstOrDefault(p => p.Id != current.Id
                    && p.ProcessName.Equals(
                        current.ProcessName,
                        StringComparison.CurrentCultureIgnoreCase));

            if (running == null)
            {
                return;
            }

            var handle = running.MainWindowHandle;
            var windowStyle = GetWindowLong(handle, -16);

            ShowWindow(
                handle,
                (windowStyle & (long)WindowStyles.Maximize) != 0
                ? ShowWindowMode.Maximize : ShowWindowMode.Restore);

            SetForegroundWindow(handle);
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetWindowLong(
            IntPtr hWnd,
            int nIndex);

        [DllImport("user32.dll")]
        private static extern int SetForegroundWindow(
            IntPtr window);

        [DllImport("user32.dll")]
        private static extern int ShowWindow(
            IntPtr window,
            ShowWindowMode showMode);
    }
}

In the code above, replace ApplicationId value with something less generic and more descriptive for your application. This value must be sufficiently unique to be used as the name for a semaphore.

The RegisterApp method attempts to open existing named semaphore. The success indicates that an instance of the application is already running. Otherwise (WaitHandleCannotBeOpenedException), the named semaphore is created.

The ActivateAppMainWindow method uses the name of the current process to find its already running instance.  The main window of which gets activated -- either maximized or restored to its original size and position.

There are at least three possible scenarios this approach covers:

  1. single executable file
  2. two copies of the executable file having same names
  3. two copies of the executable file having different names

The executable files in cases 2) and 3) do not need to be byte to byte identical. What matters is the ApplicationId value shared by the two.

The 3) case behaves differently. While multiple instances are still prevented, the running instance's main window does not get activated since the executable files in this case have different names.

* * *
While adding this functionality to WPF PRISM application, I had to make small changes to the implementation. The testing of the named semaphore existence was moved from the RegisterApp method to a separate method called TestInstance.


internal static RegisterResult TestInstance(string appId)
{
    try
    {
        Semaphore.OpenExisting(appId, SemaphoreRights.Synchronize);
        return RegisterResult.AlreadyRunning;
    }
    catch (WaitHandleCannotBeOpenedException ex)
    {
        return RegisterResult.NotDetected;
    }
}

internal static RegisterResult RegisterApp(string appId)
{
    try
    {
        var semaphore = new Semaphore(1, 1, appId);
        return RegisterResult.Success;
    }
    catch
    {
        return RegisterResult.Failed;
    }
}

The OnStartup method in App.xaml.cs was changed as follows.

protected override void OnStartup(StartupEventArgs e)
{
    var applicationId = Assembly.GetExecutingAssembly().FullName;

    if (AppLauncher.TestInstance(applicationId) == AppLauncher.RegisterResult.AlreadyRunning)
    {
        AppLauncher.ActivateAppMainWindow();
        this.Shutdown(0);
    }

    base.OnStartup(e);

    var bootstrapper = new Bootstrapper();
    bootstrapper.Run();

    AppLauncher.RegisterApp(applicationId);
}

The named semaphore must be created only after PRISM bootstrapper runs (starts the main process). Otherwise the semaphore has a very short life.