Monthly Archives: May 2011

XML file as a database – part 1

I’ve been toying with the idea to get alternative for a ‘local database’ for a standalone or even embedded database. In the past I used Jet a lot but since Microsoft is abandoning it (like some many other things including being successful… 😉 ) I started looking for alternatives. Lately I’ve been using SQL Compact a lot. It is actually nice to use and because of it SQL server roots developing for it isn’t that difficult. However, it still has one drawback that most other ‘real’ database systems have – it requires a separate install which must also be maintained separately – think about software and security updates here.

I’ve been working on a genealogical database for an uncle of mine and the current database is still an MDB file. One of the reasons moving away from this format is that Jet is not supported on 64-bit anymore – and Microsoft is not making any effort (nor would I expect it) to port the Jet database drivers to support 64-bit. Then, even the new format for Access requires installing office. This brings me to another reason I want to steer away from installing ‘separate’ things just to support a database – he (uncle) like so many other ‘normal’ computer users have no idea how to manage or maintain a database system especially if things goes wrong (and they have a habit to with normal users using them – I wonder why…). So what could I use to suit these requirements??

In the past I have considered using a plain xml file as a data store but abandoned the idea for various reasons. Things like xml’s ‘bloatness’ or lack of real database features counted against it. Now I find myself again re-looking at this but perhaps with different expectations. I don’t think using an xml file as a general database would be a good idea but for a scenario like mine it might just work – perhaps.

The question is of course how to implement this database idea. An xml file is just that – a plain text file that  has no functionality by itself. There are existing database systems that are based on xml – see nxd databases. However, none of the well established ones really support .Net as is. On the other side I don’t want to go and develop a whole new database management by myself. Perhaps there is a middle\hybrid way of doing it. From past experience I know that .Net DataSets can persist to an XML file and internally it can be seen as a mini database with support for real data types, indexing, relationships, default values including things like autonumbers etc. Transactionality is not required as the system will be single user, single instance based. Some downsides are that xml is very bloated, you cannot load just part of the data – it is either load everything or nothing and you have to be careful with which encoding you use (because genealogical data usually contain non-ascii characters 🙂 ).

Thus, I’m in the process of investigating how feasible it is to use either a plain or typed DataSet as the base of a data layer for an application. The application itself will still use normal ‘domain’ class structures to handle data internally but the data access layer will rather interface with the DataSet. I thought about just using the domain classes and serialization to persists them straight to (xml) file but then simple functionality provided by the DataSet objects would have to be coded manually (and I’m too lazy now or not in tha mood).

So stay tuned while this idea develops.

Force IIS to use NTLM

Today I’ve learned something new/old again. I’ve been having problems with an application that is running on IIS (6) where it kept on giving the error “HTTP Error 401.1 – Unauthorized: Access” when you try to access it by the machine name e.g. http://machineName/AppName. If you use the IP address then it works fine e.g. http://ipadress/AppName.

The application must use Integrated security because it only allows certain people to access it or only some people have full read and write functionality. In the code I must identify which user is logged on so it also make use of impersonation. To make sure the application itself has access to some databases it runs under an application pool that is configured under a domain account.

After some searching I came across the following kb article:

http://support.microsoft.com/kb/871179

The second workaround turns out to solve the problem. It turns out IIS6 does not authenticate the user correctly if only Integrated security is selected (anonymous is turned of) plus the application runs under an application pool that is configured with a different account (other than local system or network).

Update: Just to simplify searching for a workaround here is a copy of the text of the KB:

Workaround

To work around this behavior if you have multiple application pools that run under different domain user accounts, you must force IIS to use NTLM as your authentication mechanism if you want to use Integrated Windows authentication only. To do this, follow these steps on the server that is running IIS:

  1. Start a command prompt.
  2. Locate and then change to the directory that contains the Adsutil.vbs file. By default, this directory is C:\Inetpub\Adminscripts.
  3. Type the following command, and then press ENTER:
    cscript adsutil.vbs set w3svc/NTAuthenticationProviders “NTLM”
  4. To verify that the NtAuthenticationProviders metabase property is set to NTLM, type the following command, and then press ENTER:
    cscript adsutil.vbs get w3svc/NTAuthenticationProviders

    The following text should be returned:

    NTAuthenticationProviders       : (STRING) "NTLM"

Of course, doing this you do at your own risk 🙂

Windows Mobile 6.5.x , GMail and IMAP broken

If you are one of the ‘lucky’ ones still using a Windows Mobile 6.5 phone and reading your gmail using the standard imap interface (the default way) then your phone is screwed. Apparently Google made some change on their side that does not play nice with the imap client software on these devices. The result is that the tmail.exe process goes haywire and runs at 100% (or close) of CPU time. This has the effect that the device is first, extremely slow, the battery drains in something like just an hour or two and your gmail is not actually working anymore.

Early suggestions to temporarily fix this was to switch the receiving server (protocol) from imap.google.com to pop.google.com but even this didn’t help me. Even setting the refresh polling to manually cause the process to spike which cause the same problem. So for now I had to totally remove the gmail account just to get the rest of the phone to work normally.

Mode details here.

Hopefully they will fix it soon!

[Update: I’m glad to report it looks like they solve the problem!]

Check if user is in AD group

This is an action that often is required when you want to make sure a user account may access some resource only if they are part of some AD (OU) group. There are other ways to do this – if fact it is a lot easier if you use newer versions on the .Net framework (like 3.5 and later) but I had to create something that will still work with the 2.0 framework – thanks to some older 2003 servers that I have to manage.

I’m not going to explain too much details on how it works internally – the simple explanation is that I take the user account and loop through the list of groups the user is a ‘memberOf’. One tricky thing is to also cater for cross domain accounts/groups – like when you have a dev domain that also have groups but the user account is part of the live domain – or some combination like it.

A solution

The solution is a single helper class with one public method – IsUserInGroup(string userName, string groupName). Creating an instance of a class with one method is a bit of a waste so the class is a simple static class.

public static class DirectoryServicesHelper
{

private static bool useDomainName = false;

public static bool IsUserInGroup(string userName, string groupName)
{

useDomainName = userName.Contains(“\\”) || groupName.Contains(“\\”);
List<string> userGroups = GetGroupsForUser(userName);
if (userGroups.Contains(groupName.ToLower()))

return true;

return false;

}

The ‘useDomainName’ variable is there simply to indicate to other methods if they must cater for domain level details or not. Most of the rest of the code is inside the private ‘GetGroupsForUser’ method.

private static List<string> GetGroupsForUser(string pstrUser)
{

List<string> lstGroups = new List<string>();

string domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name;
DirectoryEntry rootEntry;
if (useDomainName && pstrUser.Contains(“\\”))
{

domain = pstrUser.Substring(0, pstrUser.IndexOf(“\\”));
pstrUser = pstrUser.Substring(pstrUser.IndexOf(“\\”) + 1);

}
rootEntry = new DirectoryEntry(“LDAP://” + domain);

using (DirectorySearcher searcher = new DirectorySearcher(rootEntry, “objectCategory=User”))
{

searcher.Filter = string.Format(“(SAMAccountName={0})”, pstrUser);
SearchResult objSR = searcher.FindOne();
if (objSR != null)
{

using (DirectoryEntry objUser = new DirectoryEntry(objSR.Path))
{

System.DirectoryServices.PropertyCollection colProperties = objUser.Properties;
PropertyValueCollection colPropertyValues = colProperties[“memberOf”];
foreach (string strGroup in colPropertyValues)
{

lstGroups.Add(GetSAMAccountName(strGroup).ToLower());

}

}

}

}
return lstGroups;

}

private static string GetDomainNameFromDE(DirectoryEntry entry)
{

if (entry == null)

return “”;

else
{

if (entry.SchemaClassName == “domainDNS”)

return entry.Properties[“Name”].Value.ToString();

else if (entry.Parent != null)

return GetDomainNameFromDE(entry.Parent);

else

return “”;

}

}

private static string GetSAMAccountName(string pstrPath)
{

DirectoryEntry objADEntry = null;
string output = “”;
objADEntry = new DirectoryEntry(“LDAP://” + pstrPath);
if (objADEntry != null)
{

if (useDomainName)

output = GetDomainNameFromDE(objADEntry) + “\\” + objADEntry.Properties[“SAMAccountName”].Value.ToString();

else

output = objADEntry.Properties[“SAMAccountName”].Value.ToString();

}
return output;

}

Summary

I’ve excluded any error checking to make the code simpler to read. For a real utility class you need to add it since AD is an unmanaged resource (as far as .Net goes) and it can throw COM+ errors as well.

With this little helper class you can simply pass it a user and group name and it will return a true or false if the user is part of the group. I’ve tested it with no domain details, partial domain details, mixed domains etc. Hopefully it can help someone else as well.

Power

Thinking about power in politics…

The tighter you hold on to power the harder you fall when you loose it

Ask anyone who has experienced it… and still lives

Scheduled tasks and restarting services

I recently had the ‘pleasure’ to have some of my maintenance scripts that restart some ‘Windows Services‘ stopped working since ‘other’ people installed stuff that creates new dependencies. The problem is that the normal commands like ‘net stop’ or ‘sc start’ are not aware of dependent services and simply fail to perform their task if the dependent service is still running. Additionally, the built in task engine for Windows does not really have much in the line of useful logging and error reporting. Most of the time you have to ‘guess’ what went wrong 😉

.Net to the rescue

Fortunately I knew from past experience that the .Net framework’s ServiceController class has the Stop and Start methods that do take into account the dependencies and also try to stop or start them as needed. So all you need is to create what is essentially a wrapper class to call these methods. Additionally you have full access to errors and can log them in any way you like. As a side bonus it might be useful to have this tool also handle batches of requests since you usually want to stop and start a bunch of related services at the same time.

To keep things simple the tool simple accepts one parameter that – a file name for the file that contain a list of the action ‘service name’s. e.g.

stop .\Winmgmt
start .\Winmgmt

Then it is a simple matter of reading the file line for line using File.ReadAllLines() method and using the first part of the line to see if the service must be stopped or started. I like things that are simple and ‘just works’.

The code also makes provision that it can stop/start services on other machines – provided the account it runs under has the right privileges. The rest of the code are there just for error handling and logging.

The code

static void Main(string[] args)
{

…initial stuff

string[] lines = File.ReadAllLines(args[0]);
foreach (string line in lines)
{

ProcessLine(line);
System.Threading.Thread.Sleep(new TimeSpan(0,0, waitBetweenServiceChangeSec));

}

}

private static void ProcessLine(string line)
{

string action = “”;
string machineName = “.”;
string serviceName = “”;
if (line.Split(‘ ‘).Length > 1) //make sure there is an ‘action’ and service name
{

action = line.Split(‘ ‘)[0].Trim().ToLower();
serviceName = line.Substring(line.IndexOf(‘ ‘)).Trim();
if (serviceName.IndexOf(‘\\’) > -1)
{

machineName = serviceName.Substring(0, serviceName.IndexOf(‘\\’));
serviceName = serviceName.Substring(serviceName.IndexOf(‘\\’) + 1);

}

if (action == “start”)

StartService(serviceName, machineName);

else if (action == “stop”)

StopService(serviceName, machineName);

}

}

private static void StopService(string serviceName, string machineName)
{

ServiceController sc;
ServiceControllerStatus resultingStatus = ServiceControllerStatus.Stopped;
try
{

LogProgress(string.Format(“Stopping the service {0}\\{1}”, machineName, serviceName), EventLogEntryType.Information, 2);
if (machineName == “.”)

sc = new ServiceController(serviceName);

else

sc = new ServiceController(serviceName, machineName);

if (sc.CanStop && sc.Status != ServiceControllerStatus.Stopped)
{

sc.Stop();
sc.WaitForStatus(resultingStatus, new TimeSpan(0, 0, waitTimeSec));
sc.Refresh();
if (sc.Status != resultingStatus)
{

LogProgress(string.Format(“The service {0}\\{1} did not stop properly in the time allowed!”, machineName, serviceName), EventLogEntryType.Warning, 2);

}
#if DEBUG
LogProgress(string.Format(“The service {0}\\{1} stopped sucessfully”, machineName, serviceName), EventLogEntryType.Information, 2);
#endif

}

}
catch (Exception ex)
{

LogProgress(string.Format(“Error stopping service {0}\\{1}: {2}”, machineName, serviceName, ex.Message), EventLogEntryType.Error, 2);

}

}

private static void LogProgress(string message, EventLogEntryType elet, int eventId)
{

Console.WriteLine(message);
EventLog.WriteEntry(eventLogSource, message, elet, eventId);

}

I’m not showing the StartService method as it is basically the same as the StopService method (with one or two extra ‘if’s).

Alternatives

I considered powershell (for 0.834 seconds like Data would have said) but it is only really useful if you run them manually since you have to ‘sign’ them and jump through a million hoops to get it working in a scheduled ‘hands-off’ way. Yes I know this was done to make it more ‘secure’ and avoid malicious stuff but it also makes it useless to solve a simple problem. With the amount of trouble you have to go through to get it working you might as well create a proper app like I did here to solve the issue.

Find a copy here.

Center an html table

Quick tip.

Since css is the more ‘accepted’ way to apply formatting to html I discovered that the normal styles like align:center or text-align:center does not work anymore to center an html table horizontally.

Instead to be able to do it you need to add the following css definition:

table
{

margin-left:auto; margin-right:auto;

}

That will make it work in Firefox but not IE (9 as tested). To get IE to display it properly you need to enclose the whole table inside another tag – like a div:

<div class=”centerme”>

<table>

</table>

</div>

plus add css for the div:

div.centerme
{

margin-left:auto; margin-right:auto;text-align:center;

}

Not pretty but it works.

WPF controls and multiple level inheritance

I’m still working on my MDI replacement idea and was trying to extend the ideas to include the WPF tabcontrol as well. Most things ported easily enough but there is one problem that came up trying to create a base class for the UserControl class that inherited from the Interface I created.

If you try to create a new WPF UserControl that inherits from the base class I created – which inherits from both WPF’s UserControl and my interface, then I get a compiler error:
“Missing partial modifier on declaration of type ‘xxx’; another partial declaration of this type exists”.

After some searching on the net (ya that old Internet thingy) I found a post on social.msdn.microsoft.com forums where the guy had similar problems. One of the responses basically explains that WPF does not support multiple inheritance. Not exactly useful. This means you cannot create base classes for WPF Windows or controls.

Thanks for this Microsoft. WPF just scored another negative point with me and a reason to stay away from it even longer. As a platform to develop applications from WPF is still too immature to be taken seriously.

ChildWindowBaseWPF

MDI interface alternative

As some developers might remember there was a time when Microsoft created/used the MDI type of user interface – MDI stands for Multiple Document Interface in case you forgot. It was widely in use during the Windows 3 and 95 areas and applications like Word, Excel and even Visual Studio used it. And then Microsoft move on… apparently abandoning the use for MDI in their own applications.

Fortunately (sort of) they still support developers creating MDI interface applications in Visual Studio 2010, but for WinForms only. WPF has no native support for it. The real problem is that since Windows 7/Vista came around they don’t actually support the MDI type of interface. Easiest way to see this is that MDI child windows are not rendered with the current Windows theme but instead shown with the ugly ‘default’ Windows theme. This is really a shame. There are still many applications or scenarios where this type of user interface is useful – I’ll admit there are many cases where alternative UI’s are better – like the tabs in web browsers like Firefox and lately IE. However, there is no ‘easy’ way to create applications using a tabbed interface in Visual Studio with all the supported things like Firefox or IE has. For one – dragging, moving and dropping tabs are not supported by default (as in WinForms – not sure about WPF). You cannot ’embed’ child Forms inside tabs (well, actually it might theoretically work as both ‘Forms’ and ‘Controls’ are internally derived from the same classes but it is going to cost some hacking…). Instead, you have to develop your entire Form as a UserControl, which is not a train smash but still…

So I’ve been digging through the Internet (electron by electron it feels like) and saw many others complain and suggesting alternatives. All the complaints aside, there are ways to do things differently but it is going to cost some work! (rolling up sleeves).

I started playing with some code to see what I can do with some trial and error. The basic approach I’m following is to use a plain old WinForm with a tab control on it. Creating tabs dynamically is easy enough in .Net. What is not so easy is the part where you must keep track of the child ‘windows’ and what is where at what time. Basically, you have to rewrite your own mini ‘Window manager’. I’ve got something working that kind of works but it doesn’t look pretty yet. It has the potential to develop into a full new MDI like framework. Keep in mind this is still work in progress and it is not complete.

IChildWindow

In order for the main or parent form to ‘communicate’ with the children and vice versa you need some standard interface. I created IChildWindow for this.

public interface IChildWindow
{

/// <summary>
/// Unique Id if used
/// </summary>
int Id { get; set; }
/// <summary>
/// Type description
/// </summary>
string Type { get; }
/// <summary>
/// Is the tab/Window pinned
/// </summary>
bool Pinned { get; set; }
/// <summary>
/// Start clean up process before closing tab/window
/// </summary>
void CloseAndCleanup();
string GetWindowTitle();
event StartCleanupDelegate StartCloseAndCleanup;
event PinnedStatusChangedDelegate PinnedStatusChanged;

}

This interface is really simple and small. The ‘Id’ and ‘Type’ properties are used to uniquely identify a ‘child window’. Actually, the ‘Id’ is only used for cases where the child can have multiple instances – say you have an editing window for persons then the ‘Id’ would be used for the person id field. In other cases you might want a window that is unique by itself in the application or reused for everything.

Pinned is used to ‘pin’ the window – if you choose ‘Close All tabs’ on the parent window it will not close the pinned tabs.

The CloseAndCleanup method is simply a way to to ensure any resources created/used on the child window gets cleaned up. GetWindowTitle is called to set the display name or text of the tab/window.

UserControlIdentifier

In order to ‘map’ type of ‘windows’ used to a name I created this simple class.

public class UserControlIdentifier
{

public string TypeName { get; set; }
public Type UserControl { get; set; }

}

It identifies the type of ‘window’ or in this case the UserControl.

WindowManager

This is a base class that manages the list of opened ‘windows’. It has methods for finding, creating, opening, and closing ‘windows’. It is generic and does not have a direct link to the type of ‘control’ used to host the new ‘window’ system. Instead, it only reference the IChildWindow interface (and UserControlIdentifier for identifying and creating windows).

The following is just a partial view of the class.

public abstract class WindowManager
{

private List<IChildWindow> windowList = new List<IChildWindow>();
protected abstract void CreateNewWindow(IChildWindow cw);
protected abstract void CloseWindow(IChildWindow cw);
protected abstract void SetWindowFocus(IChildWindow cw);
protected abstract void OnPinnedStatusChanged(IChildWindow cw);

#region Open window

public void OpenChildWindow(UserControlIdentifier uci, int id, bool reUseSimilarType)
{

IChildWindow c = FindChildWindowByTypeAndId(uci, id);
if (c != null)
{

SetWindowFocus(c);

}
else
{

if (reUseSimilarType)
{

c = FindFirstChildWindowOfType(uci);
if (c != null)
{

c.Id = id;
SetWindowFocus(c);
return;

}

}
//The create new window
IChildWindow newChild = CreateChildWindow(uci, id);

}

}
private IChildWindow CreateChildWindow(UserControlIdentifier uci, int id)
{

IChildWindow newChild = (IChildWindow)Activator.CreateInstance(uci.UserControl);
newChild.Id = id;
CreateNewWindow(newChild);
SetWindowFocus(newChild);
newChild.PinnedStatusChanged += new PinnedStatusChangedDelegate(OnPinnedStatusChanged);
newChild.Pinned = false; //and display the unpinned icon
windowList.Add(newChild);
return newChild;

}

#endregion

#region Close window

public void CloseChildWindow(IChildWindow cw)
{

cw.CloseAndCleanup();
windowList.Remove(cw);
CloseWindow(cw);

}

public void CloseAllChildWindows(bool forced)
{

for (int i = windowList.Count – 1; i >= 0; i–)
{

IChildWindow cw = windowList[i];
if (forced || (!cw.Pinned))
{

CloseChildWindow(cw);

}

}

}

#endregion

#region Find window
public IChildWindow FindFirstChildWindowOfType(UserControlIdentifier uci)
{

foreach (IChildWindow c in windowList)
{

if (c.Type == uci.TypeName)
{

return c;

}

}
return null;

}
public IChildWindow FindChildWindowByTypeAndId(UserControlIdentifier uci, int id)
{

foreach (IChildWindow c in windowList)
{

if (c.Type == uci.TypeName && c.Id == id)
{

return c;

}

}
return null;

}
#endregion

#region Pinned status
public void SetChildWindowPinnedStatus(IChildWindow c)
{

c.Pinned = !c.Pinned;

}
#endregion

}

WindowManagerForTabControl

This is the custom implementation of the WindowManager base class. It is created to handle the System.Windows.Forms.TabControl as ‘host’ to the ‘windows’ specifically.

/// <summary>
/// WindowManager implementation for System.Windows.Forms.TabControl
/// Note: the tab control must use an image list control with 3 images
///   image 0: fixed tab
///   image 1: unpinned tab
///   image 2: pinned tab
/// </summary>
public class WindowManagerForTabControl : WindowManager
{

private TabControl hostTabControl;
public WindowManagerForTabControl(TabControl hostTabControl)
{

this.hostTabControl = hostTabControl;

}

protected override void CreateNewWindow(IChildWindow cw)
{

TabPage tp = new TabPage(cw.GetWindowTitle());
((Control)cw).Dock = DockStyle.Fill;
tp.Controls.Add(((Control)cw));
tp.Tag = cw; //set inverse reference
hostTabControl.TabPages.Add(tp);
hostTabControl.SelectTab(tp); //and switch to it

}

protected override void CloseWindow(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)

hostTabControl.TabPages.Remove(tp);

}

protected override void SetWindowFocus(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)
{

hostTabControl.SelectTab(tp);
tp.Text = cw.GetWindowTitle();

}

}

protected override void OnPinnedStatusChanged(IChildWindow cw)
{

TabPage tp = null;
foreach (TabPage t in hostTabControl.TabPages)
{

if (t.Tag is IChildWindow && (IChildWindow)t.Tag == cw)
{

tp = t;

}

}
if (tp != null)
{

if (cw.Pinned)

tp.ImageIndex = 1;

else

tp.ImageIndex = 2;

}

}

public IChildWindow GetChildWindowFromTabPage(TabPage tabPage)
{

if (tabPage.Tag is IChildWindow)

return (IChildWindow)tabPage.Tag;

else

return null;

}

}

If you want to use another control or something like WPF’s tab control you would create a similar class for those types.

GlobalChildWindowController

To use all of this you need a singular place to reference the window manager implementation. In order to make it possible to reference this functionality globally in the application it is hosted in a single static class – GlobalChildWindowController.

This is really the ‘run-time’ control center of the implementation. Here the different types of windows get defined and used. The ‘hosting’ main form where the tab control is initialize this class.

public static class GlobalChildWindowController
{

private static WindowManagerForTabControl cwm;
public static void SetHostTabControl(TabControl hostTabControl)
{

cwm = new WindowManagerForTabControl(hostTabControl);

}

//Example window type
public static string PersonWindowTypeName = “Person”;
public static UserControlIdentifier PersonWindowType = new UserControlIdentifier()
{

TypeName = PersonWindowTypeName,
UserControl = typeof(PersonEditControl)

};

public static void OpenPersonWindow(int id, bool reUseCurrent)
{

cwm.OpenChildWindow(GlobalChildWindowController.PersonWindowType, id, reUseCurrent);

}

internal static void CloseChildWindow(TabPage tabPage)
{

if (tabPage.Tag != null && tabPage.Tag is IChildWindow)
{

cwm.CloseChildWindow((IChildWindow)tabPage.Tag);

}

}

}

With this class you can make the following call any place in the application:

GlobalChildWindowController.OpenPersonWindow(123);

If there is no existing ‘PersonEdit’ window open one will be opened with Id 123. If you need to have a window reused you the overload OpenPersonWindow(123,true).

ChildWindowBase

Now, to develop one of the ‘client windows’ or in this case a UserControl, I created a base class that inherits from IChildWindow and System.Windows.Forms.UserControl to make it easier to implement (otherwise you’d have to redo all the code for all controls you create.

public class ChildWindowBase : UserControl, IChildWindow
{

#region IChildWindow Members
[System.ComponentModel.Browsable(false)]
public int Id { get; set; }
[System.ComponentModel.Browsable(true),
System.ComponentModel.ReadOnly(true)]
public virtual string Type { get { return “Remember to set this value in derived class!”; } set { } }

public virtual string GetWindowTitle()
{

return string.Format(“{0}”, Type);

}
private bool pinned = false;
[System.ComponentModel.Browsable(true)]
public bool Pinned
{

get { return pinned; }
set
{

pinned = value;
RaisePinnedStatusChanged();

}

}

public event PinnedStatusChangedDelegate PinnedStatusChanged;
private void RaisePinnedStatusChanged()
{

if (PinnedStatusChanged != null)

PinnedStatusChanged(this);

}

public event StartCleanupDelegate StartCloseAndCleanup;
private void RaiseWindowClosing()
{

if (StartCloseAndCleanup != null)
{

StartCloseAndCleanup(this);

}

}
public virtual void CloseAndCleanup()
{

RaiseWindowClosing();

}
#endregion

}

To create a user control you do this:

public partial class SomeChild : ChildWindowBase
{

public SomeChild()
{

InitializeComponent();

}

public override string Type
{

get
{

return GlobalChildWindowController.SomeChildTypeName;

}
set
{

base.Type = value;

}

}

}

Conclusion

As mentioned before, this is a work-in-progress development and may not be perfect – if ever 🙂

Try it out. You can get a preview of it here.

The example shows a person view/edit window that can have multiple instances plus some others that only have a single instance. There is also a dialog box example simulating a search function. Additionally I played with a WPF example that is hosted inside an ElementHost container.

string GetWindowTitle();

Winning lotto or something

What would you do if you win a few million in the lotto?

I’ll start by paying the tax man…

And if asked – what about the rest?

They’ll have to wait…