Hello, and welcome to blue collar.
My name is Dan Elliott and I'm a software development engineer in the test organization for the .Net Compact Framework. In my nearly 14 years at Microsoft I've worked in a variety of roles in user education, testing, and development. For the past six years I've tested the execution engine for the Compact Framework (CF). I'm currently starting a new challenge: testing the GUI components of the CF base class libraries.
So why blue collar? I want this blog to address solutions for developers who are in the trenches, attempting to deliver software to end-users on time and under budget. I've worked on end-user applications both inside and outside of Microsoft. In my experience, the single most time consuming task has been determining why the system and framework software that I was relying on didn't work the way I expected. The .NET Framework has provided a great foundation on which developers can build their applications. The .NET Compact Framework has done a good job of providing a useful subset of that functionality for mobile developers. However, to be perfectly honest, no software platform is perfectly designed or engineered, particularly those as ambitious as .Net and .Net CF. I hope to use my experience with software in general and the Compact Framework in particular to provide solutions for those of you doing the real work.
So I'll jump right in. One of the comments I've heard frequently since I began working on the CF GUI base class libraries (BCLs) is "The .Net Framework has an X property (or method or event) on control Y. I really need it, but the CF version doesn't have it. Why?"
When working on devices, memory is limited. The CF provides roughly 28% of the functionality of the .NET Framework in 8% of the space. The only way to achieve that was to leave out everything that wasn't absolutely essential. That's all well and good, but you still need the functionality. Do you have to write your own control from scratch? Thankfully, the answer is usually no.
To take a specific instance, the Compact Framework version of the ListView control (System.Windows.Forms.ListView) doesn't fire the Resize event when the control's size changes. If you want to adjust the width of columns in the control when the control is resized, it would be nice to be notified. It only takes a few lines of code to remedy the problem.
Here's what we need to do:
UserControl1
Control
ListView
public partial class ListViewThatFiresResizeEvent : ListView
System.Windows.Forms.ListView
AutoScaleMode
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
OnResize
ListViewThatFiresResizeEvent
public delegate void ResizeEventHandler(object sender, EventArgs e);
Resize
public new event ResizeEventHandler Resize;
ListView.OnResize
protected override void OnResize(EventArgs e) { if (null != this.Resize) { this.Resize(this, new EventArgs()); } }
Size
Width
Height
public new Size Size { get { return base.Size; } set { base.Size = value; this.OnResize(new EventArgs()); } } public new int Width { get { return base.Width; } set { base.Width = value; this.OnResize(new EventArgs()); } } public new int Height { get { return base.Height; } set { base.Height = value; this.OnResize(new EventArgs()); } }
That's it. A similar process can be used to extend any CF control. Let me know you find this useful.
~Dan
[edited to fix formatting]
Hi Dan, is there a pratical need for Resize-event on a ListView? The event will not be fired when the windows form comes from landscape to portrait modus and vise versa. Regards! Torsten
The person that originally asked this question wanted to resize columns within the ListView when the Resize event was fired. I don't remember what was triggering the Resize event in that particular case.
Do you have any idea what happens, when a windows forms comes from portrait to landscape modus and vise versa? The properties like height, width, bounds etc. pp. there are not involved. The question is: Who resize the controls? And how? Regards! Torsten
[Edited]
When a device switches orientation, a Resize event is fired for the form. In addition, Resize events are fired for controls that support the Resize event if the control moves due to anchoring. So, in most cases, you will need to hook the Form.Resize event and move your controls manually.
Here are a couple of articles that explain further:
How to: Handle Screen Rotation
Programming Windows Mobile 5.0 Applications Using the .NET Compact Framework
Hi Dan, I got it! Damn. It occurs by using the SnApi. Comment private SystemState..., recompile and there is no error in an another project, which the user control is used. Uncomment it, recompile and Visual Studio comes with bla bla. Can you explain the behavior? (I also send this to my friend Frank Prengel from the Dev Group from Microsoft Germany.) //using Microsoft.WindowsCE.Forms; using Microsoft.WindowsMobile; using Microsoft.WindowsMobile.Status; using System; using System.Drawing; using System.Windows.Forms; namespace ControlLibrary { public delegate void ResizeEventHandler(object sender, EventArgs e); [System.ComponentModel.DesignerCategory("code")] public partial class ListViewResize : ListView { private SystemState displayRotation = new SystemState(SystemProperty.DisplayRotation); public new event ResizeEventHandler Resize; public new ListViewItemCollection Items { get { return base.Items; } } public new Size Size { get { return base.Size; } set { base.Size = value; this.OnResize(new EventArgs()); } } public ListViewResize() : base() { InitializeComponent(); //displayRotation.Changed += new ChangeEventHandler(displayRotation_Changed); } //private void displayRotation_Changed(object sender, ChangeEventArgs args) //{ // for (int i = 0; i < Columns.Count; i++) // { // Columns[i].Width = -2; // } //} protected override void OnResize(EventArgs e) { if (null != Resize) { Resize(this, new EventArgs()); } } } }
I don't know off the top of my head, but I'll look into it. I'm not sure I understand what you mean by SnApi.
Torsten,
The reason that debug builds worked and release didn't is because you have the SystemState object is #if'd out in ListViewResize.cs for debug builds.
#if !DEBUG private SystemState displayRotation = new SystemState(SystemProperty.DisplayRotation); #endif
After removing the #if !DEBUG, there are errors displaying the form in both debug and release builds. I'm looking into why the SystemState object would cause display problems in the designer.
This sounds like a good topic for a future post. I'll look into it.
One of the comments I've heard frequently since I began working on the CF GUI base class libraries (BCLs)
Dan,
I am very new to .NET CF. My problem is I need to extend the ContextMenu control so that when a submenu is selected, it is displayed on top of the parent menu - the user should only see the submenu. The parent menu should be completely hidden. What do I need to do to achieve that? Thanks.
Tuan
Tuan,
If I understand you correctly, you want to take something that looks like this:
To do this you would need to get the window handle of the flyout menu and adjust its position. Since the flyout menu is not exposed by the ContextMenu, you would have to hook the ContextMenu's window procedure and handle the messages like you would in native code. You can get an idea of how to do this in Tim Gerken's article Subclassing Controls in .NET CF 2.0.
As an alternative you might consider simply changing context menus when an item on the first context menu is clicked? For instance, if Form1 had the following context menus:
private void DisplayContextMenu2_Click(object sender, EventArgs e) { this.ContextMenu = this.ContextMenu2; this.ContextMenu2.Show(this, Control.MousePosition); }
HTH
Thank you for such a prompt reply. I think I have enough information to go from here. I really appreciate your time. Thanks.
I need to listen to key events while the ContextMenu is visible - I want to implement menuitem accelerator key feature. I tried to use the technique in the
"Subclassing Controls in .NET CF 2.0." article but my program would not compile because ContextMenu is not a control. Can you give me some directions. Thanks.