Monday, January 14, 2008

Maximizing a WPF Window to second monitor

I'm trying to develop and application that utilizes a maximized window on the second monitor.

There's a few issues here. The first is that WPF doesn't offer the same information as WinForms about monitor configuration. WinForms has SystemInformation.MonitorCount and Screen.AllScreens[i].WorkingArea. WPF has SystemParameters.PrimaryScreen[Width/Height] and SystemParameters.VirtualScreen[Width/Height] which almost works (as long as you don't have more than two monitors) but not really. So back to using WinForms API...

Secondly, the obvious solution to display a form maximized on second screen was to me the following:

                fullScreenWindow.WindowStartupLocation = WindowStartupLocation.Manual;

Debug.Assert(System.Windows.Forms.SystemInformation.MonitorCount > 1);

System.Drawing.Rectangle workingArea = System.Windows.Forms.Screen.AllScreens[1].WorkingArea;
fullScreenWindow.Left = workingArea.Left;
fullScreenWindow.Top = workingArea.Top;
fullScreenWindow.Width = workingArea.Width;
fullScreenWindow.Height = workingArea.Height;
fullScreenWindow.WindowState = WindowState.Maximized;
fullScreenWindow.WindowStyle = WindowStyle.None;
fullScreenWindow.Topmost = true;
fullScreenWindow.Show();

However, when you try that you'll end up with a topmost maximized window on your primary display, which was not what we wanted.


Turns out that we cannot maximize the window until it's loaded. So by hooking the Loaded event of fullScreenWindow and handling the event along the lines of:

        private void Window_Loaded(object sender, RoutedEventArgs e) {
WindowState = WindowState.Maximized;
}

...it works.


Oh, and you want to make certain that you are running a dual monitor configuration so you do not put the window somewhere where it is off-screen.

Wednesday, January 09, 2008

UIAutomation - testing Calculator

I recently discovered that the UIAutomation library provided in .NET 3.0 doesn't only work for managed code but for any code.

Should you so be inclined, here's how to test that calc.exe provided by Windows in fact can calculate 2+2 correctly.

        [TestMethod]
public void TestAddTwoAndTwo() {

Process calc = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = @"c:\windows\system32\calc.exe";
calc.StartInfo = startInfo;
calc.Start();
Thread.Sleep(500);

AutomationElement window = AutomationElement.FromHandle(calc.MainWindowHandle);
AutomationElement twoButton = FindAutomationElementByName(window, "2");
AutomationElement plusButton = FindAutomationElementByName(window, "+");
AutomationElement equalsButton = FindAutomationElementByName(window, "=");

AutomationElement editField = window.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"),
new PropertyCondition(AutomationElement.IsValuePatternAvailableProperty, true)));
calc.WaitForInputIdle();

InvokePattern clickTwo = twoButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
InvokePattern clickEquals = equalsButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
InvokePattern clickPlus = plusButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;

clickTwo.Invoke();

clickPlus.Invoke();

clickTwo.Invoke();

clickEquals.Invoke();
ValuePattern pattern = editField.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;

Assert.AreEqual(4, int.Parse(pattern.Current.Value,NumberStyles.AllowDecimalPoint|NumberStyles.AllowTrailingWhite));
}
        public AutomationElement FindAutomationElementByName(AutomationElement parent, string name) {
Condition c = new PropertyCondition(AutomationElement.NameProperty, name);
return parent.FindFirst(TreeScope.Descendants, c);
}


You'll also want a reference to UIAutomationClient.dll and the following using:

using System.Windows.Automation;

To find out what the application under test has eaten i.e. how to automate it, do use UISpy.exe provided with the Windows SDK .


And yes, the syntax is a tad verbose ...

Tuesday, January 08, 2008

LINQPad - Useful Linq tool

If you are using LINQ (or want to try it) and want to try out your query expressions dynamically you'll want to check out LINQPad.

Free (as in beer) and very useful!

Sunday, January 06, 2008

LINQ - DataContext.Dispose()

I'm playing around with LINQ for the moment. Actually I tried Entity Framework first, but could not get that to behave as I wanted (that is Table Per Class), so I let that rest for a while until they fix TPC support in a subsequent version and tried "plain" LINQ instead.

I can't say I'm really there yet, but one thing that bit me was that I out of old habit (or whatever) used code similar to the following:

            using (DataClassesDataContext db = new DataClassesDataContext();
{
return (from user in db.Users
where user.Name == name
select user).SingleOrDefault();
}

..and I thought that all was well. However, when testing a little bit more I got  ObjectDisposedException:s when returning

return (from user in db.Users select user).AsEnumerable();

instead of

return (from user in db.Users select user).ToList();

Turns out that even though DataContext implements IDisposable, you should not use a DataContext in a using statement or directly call .Dispose() or you'll end up with lots of brokenness.


(In addition I got all kinds of attaching and detaching issues, but I think I've sorted them now. Did I already tell you that this is my first attempt of using LINQ non-trivially?)

Saturday, December 22, 2007

TimeSpan.Seconds vs .TotalSeconds

The difference between the Seconds property and the TotalSeconds property is (or at least should be) pretty obvious, but based on experience it is a common bug to use .Seconds when you actually mean .TotalSeconds. For the readers out there that hasn't gotten the difference, think of a timespan of value 1 minute 23 seconds - here .Seconds is 23 and total seconds is 83.

As a rule of thumb, most often it's the Total variant you want, and yes, the same applies to all the other members too, (e.g. .Minutes, .Milliseconds vs. the corresponding .Total-prefixed ones)

Friday, December 21, 2007

"Practical Functional C#"

I just found an interesting blog post series about practical functional C#. It starts right here. Maybe I've missed something, but this feels like a fresh breath, being really down to earth and real world. I'm looking forward to future posts.

Friday, December 14, 2007

"Is there a constant for tab like Environment.Newline?"

..was a question a co-worker asked the other day. My first answer was no, as it is not really needed as a tab does not change between platforms as newline might (think Mono).

Then I realized, there actually *is* one, so I gave the following instructions:

  • Add a reference to Microsoft.VisualBasic.dll
  • add a using Microsoft.VisualBasic; statement
  • use Constants.vbTab

(And to avoid any misunderstandings, no, this was not a serious suggestion.)