Thursday, February 26, 2009

Testing for a Toggled Key

There are several keys on the keyboard that can be in a toggled state: num lock, scroll lock, cap lock and insert. There is a convenient method in the Control class that will get the state of the button: Control.IsKeyLocked(key). The key parameter can be one of Keys.CapLock, Keys.NumLock, Keys.Scroll and Keys.Insert. The method returns true if the key is in the toggled state, otherwise it returns false.

According to the MSDN documentation, the method will throw a NotSupportedException if the key is not CapLock, NumLock or Scroll; however, Insert also works and does not throw an exception.

This method has been available since .NET 2.0. For earlier versions, it was necessary to do some interop with the user32.dll. There is a method that returns a bit field for the state of a key. For keys that can be toggled, the lowest bit in the field will be 1. Use a bitwise & operation to isolate the bit.

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern ushort GetKeyState(int keyCode);

//From winuser.h
private const int VK_INSERT = 0x2D;
private const int VK_NUMLOCK = 0x90;
private const int VK_SCROLL = 0x91;
private const int VK_CAPITAL = 0x14;

public static bool IsKeyToggled(int nKey)
{
return (GetKeyState(nKey) & 0x01) == 1;
}

The hex codes for the keys can be obtained from winuser.h. In VS08, I found this file under the SDK folder for smart phones and pocket PC.

For Vista, there is also a Keyboad class that is part of the System.Windows.Input namespace. References to the presentation core and to the windows base dll's must be made. The presentation core contains the Keyboard and Keystate classes. The windows base contains the Key class. Be careful with the Key class, since there is also a Key class in System.Windows.Forms.

Keyboard.GetKeyStates(Key.CapsLock) == KeyStates.Toggled

 

Thursday, February 19, 2009

Running WPF in a Browser

Aaarrrggghhhh!!!!! Microsoft Security Exceptions!

I have been trying to get my first example of an XBAP file running in a browser. I am using the book Essential Windows Presentation Foundation, by Chris Anderson. I did not have any problems with Chapter 1 and was able to download the source code for the more complicated examples at the end of the chapter.

Chapter 2 does not have any source code available. I was trying to run a very simple "Hello World" application. I was still using the command line to run my examples, just to get a feel for the syntax of the project and application files. I ran the application as an exe without a problem. Next, I added the property in the project file to allow the app to run in the browser.

<PropertyGroup>
<HostInBrowser>true</HostInBrowser>
</PropertyGroup>

When I ran it, I received an error about signing the manifest.

Error 3 The ClickOnce manifest for XAML Browser Applications must always be signed. You must specify properties: SignManifests (value set to True), and either ManifestKeyFile (with the name of your key file) or ManifestCertificateThumbprint (hexadecimal thumbprint value in SHA-1 format, of key file). Alternatively, you may use your IDE's Publish Wizard or Signing options.


I referred back to the book and saw a footnote about singing manifests using Visual Studio. I opened Visual Studio and created a new WPF Project. A lot of files were created for me. I signed the manifest from the Properties -> Signing tab. I created a temporary certificate. I ran the simple application as an exe and it worked. I edited the csproj in a text editor and added the code for running in a browser. I tried to run the app from VS, but could not, since it is meant to be run in the browser. I found the XBAP file in the file system and double-clicked it. The browser opened and I received this error.

System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.UIPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

Looking further in the error list, I noticed that the assembly did have UIPermission, but only for save top level windows. I then remembered that the example from the book used Page as the base class, but that the default application in VS used Window. I edited the project so that it used Page instead of Window. I still had the same error.

When I had developed this from a different computer, I received a different error about the assembly not allowing partially trusted callers to use it. I had resolved this on the other computer, so I thought it might be a problem on this one. There is a very detailed explanation of the problem on the web. The trick is to add the AllowPartiallyTrustedCallers attribute to the code-behind file, at the assembly level.

using System.Security;
[assembly: AllowPartiallyTrustedCallers]

I still had the error. I had seen some posts on the web about similar errors that referred to publishing the application, so I published it, using the Build menu. The URL that was generated had an extra " at the end, so it failed. After removing that, I was given a directory listing. I double-clicked the XBAP file and it worked.

Since I had made so many changes before the application worked, I backtracked to see which one(s) had done the trick. The only one that I did not need was for the PartiallyTrustedCallers. Apparently, the computer I am using now has different access rights than the one I was using earlier, so I will keep the assembly attribute in the final solution.

Looking back at the first error I received, I see that it suggests using the IDE's signing or publishing wizards to sign the manifest; apparently, both signing and publishing are needed.

PS. There was another error that I saw referenced on the web about the application cache. At some point I also tried clearing it. The process was to close the browser, open the VS commmand prompt and execute the command mage -cc. The command took a minute to complete. I do not think this had anything to do with getting my example to run.

PPS. I have reconfigured the application for the original computer: I changed the app from a base class of Window to Page and published the application. I did not need to add the partially trusted attribute. To be more specific, I ran it with the attribute, then I removed the attribute, rebuilt, republished and it still ran.
 

Tuesday, February 17, 2009

ASP.NET

I have been developing web applications for many years. I started with Perl many years ago; for the past few years, I have been using Servlets and JSPs. I decided to port an application to ASP.NET, just to see how it went.

I prefer the MVC architecture and have found that in order to implement it, I need to bypass the rich control set that ASP.NET offers. The controller in MVC needs to get all of the requests; since anything with runat="server" is consumed by the associated code file, they cannot be used with a controller.

I use a separate class for the model; accessing this from an ASP is complicated, since a cast is required and the class must be registered in the page. I prefer Expression Language in JSPs.

I talked to a friend who uses ASP.NET all the time and he did help me out with Server.Transfer, which can be used in place of Response.Redirect. However, there is a bug in the Server.Transfer when the form data is to be forwarded. I found a comprehensive discussion of Server.Tranfser.

I will continue to explore. The friend I mentioned suggested that WPF can be used to implement MVC. I will look into that.

Sunday, February 15, 2009

Using LINQ in ASP.NET

I have a new book: C# 2008 by Mei-Weng Lee, WROX. I am playing around with LINQ in ASP.NET. The first step was to remember how to access SQL Server and SQL Server Express; I had already installed both of these some years ago. When I opened the Server Explorer in VS08, the Data Connections was empty.

I followed the instructions in the book to download pubs and Northwind databases, although I was sure I already had Northwind installed. The key step was to run the installation scripts from a VS08 command prompt.

sqlcmd -S .\SQLEXPRESS -i installpubs.sql
sqlcmd -S .\SQLEXPRESS -i installnwnd.sql

After returning to the Server Explorer, I still did not have any data connections, so I added one. I used SQL Server as the connection type; I chose SQLEXPRESS as the server; I chose the pubs database. Now I have a connection.

I used the visual designer for the .dbml file and dragged two tables onto it. After saving, the designer file had created a class with declared properties for accessing the tables.

I had to start again: at first, I selected new project, instead of new web site. Much better as a web site, I am now seeing all the prompts that I am supposed to see. After I understand this better, I will need to analyze the difference between a project and a web site.

I was able to access the table from ASP. I see that LINQ can create classes based on tables, but can it create tables based on classes? I have not seen any information on this. The other problem I have is that a lot of code is written in the ASP and not in a separate controller for the business logic.

I will look into using Hibernate with .NET. I will also look into moving all the business logic into one code-behind file and put all the validation in the data class.

Thursday, February 12, 2009

Stylesheet for Printing

I never questioned how some HTML pages print everything on the page and others only print the relevant information. I just learned that there is a media attribute in a style sheet tag that controls to which media the style will apply.

The options for the media attribute are
all
Suitable for all devices.
aural
Intended for speech synthesizers. See the section on aural style sheets for details.
braille
Intended for braille tactile feedback devices.
embossed
Intended for paged braille printers.
handheld
Intended for handheld devices (typically small screen, monochrome, limited bandwidth).
print
Intended for paged, opaque material and for documents viewed on screen in print preview mode. Please consult the section on paged media for information about formatting issues that are specific to paged media.
projection
Intended for projected presentations, for example projectors or print to transparencies. Please consult the section on paged media for information about formatting issues that are specific to paged media.
screen
Intended primarily for color computer screens.
tty
Intended for media using a fixed-pitch character grid, such as teletypes, terminals, or portable devices with limited display capabilities. Authors should not use pixel units with the "tty" media type.
tv
Intended for television-type devices (low resolution, color, limited-scrollability screens, sound available).
The media type can be included in the stylesheet with
@media print{
style1 {
...
}
}
Alternatively, separate style sheets can be created for each media type.
<link href="styles/screen.css" type="text/css" rel="stylesheet" 
media="all" id="screenCSS" />
<link href="styles/print.css" type="text/css" rel="stylesheet"
media="print" id="printCSS" />


A javascript trick can be used to make the current page look like print preview; kudos to the creator. The idea is to change the media type of the 'print' sytlesheet to 'all' using javascript.

I would make one addition to the technique: use three style sheets. The third stylesheet would be for print preview. This is necessary in the event that you don't want to print the link or button that toggles the style sheet.
<link rel="stylesheet" href="styles/all.css" type="text/css" 
id="screenCSS" media="all">
<link rel="stylesheet" href="styles/print.css" type="text/css"
id="printCSS" media="print">
<link rel="stylesheet" href="styles/preview.css" type="text/css"
id="previewCSS" media="preview">
<script language='javascript'>
function togglePrintPreview()
{
var currCSS = document.getElementById('previewCSS');
if(currCSS.media == 'all')
currCSS.media = 'preview';
else currCSS.media = 'all';
}
</script>

Wednesday, February 11, 2009

Multithreading in C#

I am reading the book C# 2008, Programmer's Reference, by Wei-Meng Lee. I have just finished the chapter on threading. The book covers the material very well. It does not have a discussion of the process thread pool, but it does cover the different ways to implement multi-threading. The most convenient method is to use the BackgroundWorker component; however, for more advanced threads, the Monitor class is most useful.

The Monitor class has the methods Enter, Exit, Wait and Pulse. They all use an object for locking; use a static object that both threads can access. Use Enter and Exit around the critical section. Use Wait in the event that one thread needs to wait for the other thread to do something before it can continue. The other thread must call pulse when it has completed the task that waiting thread needs to be done.

The lock method is a simple Monitor that only has Enter and Exit.

For some functions, like increment and decrement, there is the Interlock class, which has static methods that are thread safe.

Sunday, February 8, 2009

Control Library is more Useful than ClassLibrary

A ClassLibrary project and a UserControl project are not much different. Each can contain user controls and forms. There was a reference to a problem with using user controls in a class library.

There is also a reference to a problem with using a control library and a class library. I also had a problem with this, since each one referred to the other; after doing a clean, I was unable to rebuild.

The only differences I have observed are some different references. The class library has a reference to System.Linq.

I will stick to a user control library and add general classes to it, too.

As for visual inheritance of a form in the library, the controls that have protected access will also be set in the InitalizeComponent of the child, so the child can change them; private controls will not be referenced in the child.

The components container in the child class will not be instantiated until a control or component is added to the child form.

I have been modifying a base form and adding child forms based on it. After I have added a child by creating an inherited class, then made changes to the base and then added another child by creating an inherited class, there can be a reference error when adding the second child; resolve this by cleaning the solution, rebuilding the control library and rebuilding the solution.

Visual Inheritance of Statusbars and Toolstrips

I wanted to create a base form that contained a default menu and a default status bar. When I inherited from this form, I wanted to be able to customize the menu and the status bar. After many attempts to get this to work, I realized that it cannot be done in the designer.

I watched an interesting video on Visual Inheritance that confirmed that I was doing things correctly. After I implemented the tutorial for an inherited button, I realized that there was something wrong with menus and status bars.

After searching google for a while, I stumbled on a discussion on the topic. The reference from there was the goldmine: it can't be done!

Back to the drawing board. I will look into adding a second menu to the child form and then adding the menu items to the main form in the base class. The child can still access the menu, it just can't access it at design time in the designer. Sigh.

I have devised a workable solution for the menu strip.
  1. Create a context menu in the child class in the designer; this will support visual editing.
  2. Create a menu item at run time in the child for a new top level menu item.
  3. Set the DropDown event as the context menu.
  4. Insert the top level menu item into the main menu.
//Place in constructor or load event handler
ToolStripMenuItem menuItem = new ToolStripMenuItem("Tools");
menuItem.DropDown = contextMenuStripTools;
this.menuStripBase.Items.Insert(0, menuItem);
Here is another idea:
  1. Add a menu strip to the child. Add all the menu items to it.
  2. Add all the items from the main menu to the base menu.
  3. Access the items in the main menu in reverse order, since each item is moved to the base menu when it is inserted. A foreach cannot be used, since the item collection changes. AddRange won't work for the same reason.
 int count = 0;

 //Use this for loop, or a foreach, to see it crash
 //for (count = 0; count < max; count++)
 //A reverse pass through the items will do the trick
 for (count = menuStripMain.Items.Count - 1; count > -1; count--)
 {
   this.menuStripBase.Items.Insert(0, menuStripMain.Items[count]);
 }

Update: 

The ToolStripManager class has a method that does menu merging like MDI applications.

public static bool Merge(
    ToolStrip sourceToolStrip,
    ToolStrip targetToolStrip
)


ToolStripManager.Merge documentation. Notice that it is a static method.

Saturday, February 7, 2009

UserControl Container at Design Time

Today I learned how to create a UserControl in C#.NET that can act as a container control at design time. In other words, the control will act like a group control; otherwise, when a control is dropped onto it, it will pass to the container control that is behind the control.

Create a UserControl.
Add a reference to System.Design; this will add the System.Windows.Forms.Design.ParentControlDesigner designer to the application. Use this to adorn the class definition of the user control.

[Designer(typeof(System.Windows.Forms.Design.ParentControlDesigner))]
public partial class ControlMovable : UserControl

Now, the user control will act as a container at design time: when controls are dropped onto the user control, they will be added to the ControlCollection class in the user control.

In order to handle events in the user control class for the controls that are added to it at runtime, handle the ControlAdded event and ControlRemoved event. Register and remove control events in these handlers.

For example, the mouse down events are sent to the controls directly. In order for the user control to handle the MouseDown event, register a MouseDown handler with the e.Control member from the event args sent to the event.

private void ControlMovable_ControlAdded(object sender, ControlEventArgs e)
{
  e.Control.MouseDown += this.ControlMovable_MouseDown;
}

private void ControlMovable_ControlRemoved(object sender, ControlEventArgs e)
{
   e.Control.MouseDown -= this.ControlMovable_MouseDown;
}


Followers