Main

March 30, 2006

Good post on User Controls

Roland Weigelt has a good post here about VS 2005 User Controls.

Remember to add Browsable, DefaultValue, Category, and Description attributes to public properties.

Browsable and DefaultValue in particular can help you design your control the way you want without having the designer run code it shouldn’t at design time.

 

January 29, 2006

First Effort at Smart Device Development

Just finished my first mobile .NET application.

Things that were easy:

·        Creating a skin for the Treo 700w. I happened to download SOTI Pocket-Controller Professional which had a skin for remote access. I grabbed its bmp file and found the folder that defined the existing skins (C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Deviceemulation\). A quick edit of an existing skin XML file and some Photoshopping of the borrowed skin image followed by using the ToolsàDevice ToolsàForm Factors and Devices UIs in Visual Studio 2005 to copy an existing emulator configuration (Windows Mobile 5.0 Pocket PC Phone Square Emulator) and assign it a new Form Factor.

·        Put an application CAB file on a web server. Using IE on the phone to browse the CAB file triggers a download dialog. Check the open after download box and the installer starts automatically.

·        Getting .NET 2.0 framework installed on the phone.

o       Deploying an application directly to the device triggers installation of the .NET 2.0 runtime.

Things that were hard:

·        Getting internet connectivity within the emulators. Remember to have the emulator cradled (use the ToolsàDevice Emulator Manager) and within the emulator enable a network adapter (FileàConfigureàNetworkàEnable NE2000 PCMCIA network adapter…

·        Understanding the difference between all the available emulators. A Smartphone has a limited UI but includes a phone. Pocket PC has an enhanced UI (it assumes the ability to enter keys on a keyboard, graphical or otherwise). And a Pocket PC Phone has both the enhanced UI and a phone.

·        Getting an ASP.NET 2.0 project deployed from a development server to a deployment server with mixed 1.1 and 2.0 based web apps.

o       Copying doesn’t seem to do anything about configuring the virtual directory or file security settings.

o       Publishing is hidden on one of the menus. It doesn’t do the whole thing either.

o       It would be great to have something generate the xml file from which either the virtual directory or web site was configured.

·        Avoiding ObjectDisposed exceptions when shutting down the windows mobile application. There’s a web request pending at the time of shutdown. The request uses a thread pool work item to implement the request. It looks like the request is completing only to find its world disposed. Resolved by calling Abort on the request, not on the thread. And arranging for the thread to exit cleanly.

·        A related issue is what event’s fire when a windows mobile application is minimized (x in corner is clicked) and when the red button is pressed to turn off the screen. An application continues to run if the OK or minimize button are used to hide the application window while leaving it active. Execution is suspended by the red power button. Execution resumes when the red button is pressed again.

·        Icon colors.

o       Use photoshop to convert the image to indexed colors with the Windows System palette.

o       For some reason, icons installed in the emulator seem to be sticky. They don’t update when the application that owns them is updated.

·        The screen on the Treo 700w is 240 x 240 pixels but after the top and bottom bars are lost to the environment, there’s only a 240 x 188 left. Is there any way to get that space back? When the window form is running in maximized mode, it seems to have the top bar in its client rectangle but there’s still a bar visible.

·        Figuring out how to do resources for localization correctly. The breakthrough was finding the localizable property on a Windows.Forms.Form. Turning this on causes magic to happen in the generated code. Selecting a non-default Language property automatically adds a new resource file. Haven’t chased down the whole satellite assembly building and deployment concept yet. Since a smart device app must stay small, you never want to drag around resources that aren’t used.

·        Getting the application shortcut in the right folder.

o       When you create a Smart Device CAB project to setup a smart device application, the default file system view doesn’t contain the Programs Folder. You can add it manually. This is where the application shortcut has to go.

·        Getting a \r\n sequence into a string resource J. I was moving the string from C# code to the resource editor. “\r\n” was interpreted as a literal, so I tried \u000D\u000A and finally 
. Looking at the resource file in the xml editor showed the last attempt being escaped so I un-escaped them and voila! All I had to do was hit the enter key when replacing the original “\r\n”. Doh.

Things I don’t know how to do yet:

·        Signing the application and CAB file in such a way that the phone doesn’t display the unknown publisher dialog. Many commercial packages behave the same way.

·        Building a smart device installer that triggers an ActiveSyn install. Right now the Smart Device CAB setup project requires that you copy the CAB to the device and run it there. It seems you build an ordinary Windows Setup project but there’s some magic involved in communicating an .ini file to ActiveSync that I just haven’t come across yet.

 

December 06, 2005

Event registration details in C#

What happens if you add a delegate with an event more than once? The delegate will be invoked as many times as it is registered when the event “occurs”.

What happens if you remove a delegate from an event after adding it more than once? One registration is removed at a time.

What happens if you remove a delegate from an event if it has never been registered or if it has already been removed? Nothing.

Since delegates are equal so long as the wrapped methods are the same, it is not necessary to save the actual delegate instance that was added if you intend to remove it later.

 

        public class C1 {

            public event EventHandler E1;

            public void InvokeE1() {

                if (E1 != null) E1(this, new EventArgs());

            }

        }

 

        int invocations = 0;

 

        public void h(object sender, EventArgs args) {

            invocations++;

        }

 

        [TestMethod]

        public void TestRepeatedEventHandlerAddRemove1() {

            C1 c1 = new C1();

            c1.E1 += new EventHandler(h);

            Assert.AreEqual(0, invocations);

            c1.InvokeE1();

            Assert.AreEqual(1, invocations);

 

            // Verify that adding an event handler is invoked as many times as it is added.

            c1.E1 += new EventHandler(h);

            c1.InvokeE1();

            Assert.AreEqual(3, invocations);

 

            // Verify that removing an event handler removes only one copy at a time.

            c1.E1 -= new EventHandler(h);

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

            c1.E1 -= new EventHandler(h);

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

 

            // Verify that removing a non-existant event handler does nothing.

            c1.E1 -= new EventHandler(h);

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

        }

 

        [TestMethod]

        public void TestRepeatedEventHandlerAddRemove2() {

            // Verify that it doesn't matter whether the identical delegate instance is

            // used instead of just an "equal" delegate.

            C1 c1 = new C1();

            EventHandler eh = new EventHandler(h);

            c1.E1 += eh;

            Assert.AreEqual(0, invocations);

            c1.InvokeE1();

            Assert.AreEqual(1, invocations);

            c1.E1 += eh;

            c1.InvokeE1();

            Assert.AreEqual(3, invocations);

            c1.E1 -= eh;

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

            c1.E1 -= eh;

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

            c1.E1 -= eh;

            c1.InvokeE1();

            Assert.AreEqual(4, invocations);

        }

 

November 27, 2005

C# 2.0 Transactions framework

Pointer for future reference: Volatile Resource Managers in .NET Bring Transactions to the Common Type, by Juval Lowy

 

October 28, 2005

Avoiding Out of Memory Exceptions in .NET

Updated 2005-11-16 15:33 Wed

One solution to automatically setting the /LARGEADDRESSAWARE switch in the copy of an exe that gets built into a Windows Forms setup file is to add the following line to the project’s post-build event:

editbin /LARGEADDRESSAWARE "$(ProjectDir)obj\Debug\$(TargetFileName)"

This appears to work because the setup project takes its copy of the exe (primary project output) from under the “obj” folder, and not the “bin” folder.

Updated 2005-11-15 08:57 Tue

Getting access to more memory for your .NET 2.0 windows forms applications using the /LARGEADDRESSAWARE switch is described below, but there’s a problem with distributing applications that use this switch.

If you use the method described below to automatically set the switch each time you build a project in Visual Studio 2005, you will discover that it fails to set the switch in executables included in setup projects.

It appears that project build events are not executed as part of building a setup project that includes their primary outputs.

 

Running a simple .NET (2.0 beta 2) application that allocates 1MB buffers until the OutOfMemoryException is thrown gives me these results (on Windows XP SP2):

Scenario

Successful Allocations

Default configuration, running under Visual Studio 2005 beta 2

1605 MB

Default configuration, running from the command line

1704 MB

With /3GB and /LARGEADDRESSAWARE switches

2685 MB

 

A “pure” .NET application appears to be “largeaddressaware”-safe. If your application uses third party libraries, they may not like receiving addresses that exceed 2GB.

Making maximum use of RAM on a Windows XP system with more than 2GB or RAM requires a few extra steps:

·        /3GB Switch

Windows XP looks for a /3GB switch in the boot.ini file when it loads to determine whether to partition the 4GB address space as 2GB user / 2GB system (the default), or as 3GB user / 1GB system.

To turn on this switch:

o       Control PanelàSystemàAdvancedàStartup and Recovery SettingsàEdit

o       Add “ /3GB” to the end of the line following the “[operating systems]” section.

o       Restart the machine for the change to take effect.

·        /LARGEADDRESSAWARE Switch

An executable must have this switch enabled to make use of the extra memory beyond 2GB.

To turn on this switch:

o       Add to PATH environment variable:

§         c:\Program Files\Microsoft Visual Studio 8\common7\ide

§         c:\Program Files\Microsoft Visual Studio 8\vc\bin

o       In Visual Sutdio, add a Post-Build Event:

§         editbin /LARGEADDRESSAWARE “$(TargetPath)”

Links:

http://www.dotnet247.com/247reference/msgs/55/276803.aspx

 

 

September 04, 2005

Creating a Word Add-in using Visual Studio 2005 beta 2

Visual Studio 2005 beta 2 includes the beta 2 version of Visual Studio Tools for Office, but it lacks a template for creating a Word Add-in.

Here’s how you can create one manually:

1.      Create a new Class Library project.

2.      Go to Application tab of the project’s properties:

a.       Click Assembly Information…

b.      Click “Make assembly COM-Visible

3.      Go to Build tab of the project’s properties:

a.       Check “Register for COM interop”

4.      Add references to:

a.       C:\Program Files\Common Files\Microsoft Shared\MSEnv\PublicAssemblies\extensibility.dll

5.      Add “using” statements to the class file for the following:

using Extensibility;

using System.Runtime.InteropServices;

6.      Add a Guid attribute to the class:

[Guid("E1234594-4A14-4a6f-8612-6019EB11CE70"), ProgId("MyDomain.MyWordAddInClass")]

7.      Create a setup project for the class library.

a.       Under the Registry settings to be created by the setup project add the following key:

                                                               i.      HKEY_CURRENT_USER/Software/Microsoft/Office/Word/Addins/MyDomain.MyWordAddInClass

b.      Under this key, create the following values:

                                                               i.      Description (string) = “My Description”

                                                             ii.      FriendlyName (string) = “My Friendly Name”

                                                            iii.      LoadBehavior (DWORD) = 3

That’s it. You should be able to build, install, and uninstall the add-in.

 

August 28, 2005

Automating Word, Add-In vs. Template

At its simplest, the problem is to run some code when CTRL-ALT-A is pressed while editing a Microsoft Word 2003 file.

The code that runs wants to be written in C# and it’s purpose is to modify the content and styles of the current document.

In my first solution, I created a Word Add-In (using Visual Studio Tools for Office) and Visual Studio 2003. The Add-In has to register its DLL under the right Office keys to be found by Word. When Word starts, the assembly’s Connect method gets called. It proceeds to install a new toolbar into Word containing a few buttons. It’s easy to connect the Click event of the buttons with the C# code I want to run. Getting the code to run in response to a CTRL-ALT-A is considerably harder.

The first trick was to discover that a macro of the form below will invoke the C# event handler assigned to a toolbar button:

Sub TonesNotesNew()

    Dim cb As CommandBar

    Set cb = Application.CommandBars("TonesNotes")

    Dim cbc As CommandBarButton

    Set cbc = cb.FindControl(Tag:="New")

    cbc.Execute

    cbc.State = msoButtonUp

End Sub

The last piece of plumbing is to assign CTRL-ALT-A to invoke the macro “TonesNotesNew”.

The second time around I implemented the same functionality as a Word template file which is one of the new Visual Studio 2005 beta 2 project templates. The template file now holds the macros, the styles I use for this functionality, and the C# assembly that does the actual work.

 

 

August 23, 2005

LoaderLock MDA warning in VS 2005 beta 2

After making some fairly innocuous changes, I started getting the following error dialog during application startup running within the VisualStudio 2005 beta 2 IDE:

LoaderLock was detected

Message: Attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function.

See C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215\sdk\bin\mdaBoilerplate.exe.mda.config for documentation.

 

Commenting out the code executing at the time of the exception moved it to a new location in the startup code.

I tested the same code built on a second PC with similar general configuration (but obviously many minor differences) and the problem did not occur.

So I followed the instructions in the MSDN help article referenced by the error dialog…

Added this key:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]

"MDA"="0"

Following this article:

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxdebug/html/76994ee6-9fa9-4059-b813-26578d24427c.htm

This masks the problem. I don’t know if it was a bug in the detection code or a bug in the initialization code that just happens to skate by if ignored. I suspect the later.

A bit scary.

 

 

Amazing post on startup & shutdown

August 22, 2005

How to convert a hex string to an integer

The MSDN page that tries to answer this question is an absolutely horrible example of how a compact and simple piece of information can be made almost impossible to understand: How to use the Int32.Parse method to convert the string representation of a hexadecimal integer to a decimal integer by using Visual C# .NET

Here is what it should have said:

To convert a hexadecimal string to an integer:

string s = "a0"; // 160 in hexadecimal

int i = int.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier);

 

NOTE: If the string includes the standard "0x" prefix, a System.FormatException will occur.

 

August 13, 2005

Publishing ASP .NET 2.0 to Windows XP Pro

On a newly configured Windows XP Professional system, the following steps may help you configure it to accept ASP .NET 2.0 applications published from a remote machine:

1.      Add IIS with FrontPage Server Extensions to the Windows XP configuration using the Add/Remove Windows Components tab on the Add or Remove Programs control panel.

2.      Run “C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215>aspnet_regiis –i” if unsure about ASP .NET integration with IIS.

3.      Check that the IUSR_<machine_name> and IWAM_<machine_name> accounts have access to the IIS wwwroot folder (typically c:\Inetpub\wwwroot). IUSR_ at least requires read & execute access.

a.       If Windows XP is using simple file sharing, you may not see the Security tab in the folder Properties dialog and won’t be able to set individual NTFS account access permissions. Uncheck the “Use simple file sharing” folder option (Explorer à Tools à Folder Options à View tab).

4.      Make sure any specific pages you’re trying to access have anonymous access enabled for them (Administrative ToolsàInternet Information Services à Default Web Site à Properties à Directory Security à Edit… à Anonymous access checked.

5.      If the Windows XP Firewall is enabled, create an exception for HTTP. Advanced à Local Area Connection à Settings… à Web Server à Edit (if needed) make sure machine name or IP is correct. Machine name is fine even if access is via IP address (or presumably DNS).

At this point you should be able to use the Visual Studio 2005 beta 2’s Build à Publish. Use an http:// path to the web app’s remote root.

 

August 08, 2005

Generating Patch Files for MSI Setup Files

Building an installer for just about anything with dotNET produces a multi-megabyte setup file which contains mostly dead-weight in terms of original content.

I found myself wanting to avoid transferring these large files each time I made a small update to a program on a remote PC, so I went looking for a compact and simple patch generating tool.

I ended up finding bsdiff.exe and bspatch.exe which require bzip2.exe. Lean, mean, and exactly what I wanted.

 

July 07, 2005

Visual Studio 2005 Beta 2 Problems, Properties Settings of User Types are Impossible to Add

Opened by ToneEngel on 2005-06-16 at 06:02:59    
On the Settings tab of the application Properties GUI the Browse... option on the Type column combo box brings up a Select a Type dialog that does not include types defined in all referenced assemblies or types defined in the application project.

Beta 1 allowed these types to be selected for property settings and the functionality worked. After conversion to beta 2, these user types appear in the combo box list, but not the browse list.

Manually editing the settings XML file can cause the types to appear in the combo box list.

 

Edited by Microsoft on 2005-06-17 at 00:25:17

The Microsoft Sub-status is now "Reproduced"

Thanks for reporting this bug, we have been able to repro this issue and are investigating.

Thank you,
Vivek, VS2005 Product Team.

 

Resolved as Won't Fix by Microsoft on 2005-06-24 at 10:37:11

The issue with using types from referenced assemblies showing up was found too late to be fixed in the Beta2 release (see http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?feedbackid=45bfedf6-825b-478b-861e-c2be77bcbdd9) It has been fixed since, and using types from referenced assemblies will work in the RTM release of Visual Studio 2005.

Being able to use types defined in the current project is a very good suggestion, but given our current schedule, we will unfortunately not have time to address this in the Visual Studio 2005 release. I will make sure that we revisit this for the next release of Visual Studio.

There are inherent problems with types that are defined in the same project/in project-to-project references in that they are very likely to change. The settings designer actually has to be able to create instances of the current type in order to function correctly (it needs that information in order to be able to show you the right editor, if any, to edit values as well as to be able to write the default values in code and in the app.config file).

As a work-around, if you really need to use types defined in the current project, you can use the user-editable part of the settings class (the file that opens if you push "View Code" in the settings design) and manually add the settings to this class:

<Global.System.Configuration.UserScopedSettingAttribute(), _
Global.System.Configuration.DefaultSettingValueAttribute("(Optional) serialized representation of an instance of this type")> _
Public Property Setting() As MyTypeDefinedInTheCurrentProject
Get
Return CType(Me("Setting"),MyTypeDefinedInTheCurrentProject)
End Get
Set
Me("Setting") = value
End Set
End Property

 

 

 

June 15, 2005

Visual Studio 2005 Beta 2

Working with beta 2 of Whidbey (Visual Studio 2005) has been difficult so far, surprisingly difficult given how comfortable I had become at developing Windows.Forms based applications with beta 1.

I went back to my notes from the time I started using beta 1 of Whidbey to remember how many problems I had to learn to live with. Like many things, familiarity breeds comfort.

Among the problems I’ve had are:

·        Enabling break when an exception is thrown from C++ or Win32 caused an InvalidDeploymentException to be thrown when accessing simple Properties.Settings.Default properties during application startup. The problem disappeared when I cleared the DebugàExceptions checkboxes, but not before spending several hours trying to work around the exception. And now I’m hitting a vanished XML serialization assembly.

See http://www.dotnet247.com/247reference/msgs/42/211509.aspx

·        Source code coloring in the editor keeps going away for some of my source files. If I cut and paste the contents between source files it comes back. But only to disappear again if I reload the project. The code compiles and runs without trouble.

·        The GUI for defining settings under the application properties editor doesn’t allow settings to be declared from user types. By following the example created by converting a beta 1 application, I was able to manually edit the xml files to cause the type to appear in the list of choices.

·        There are enough changes to the Windows.Forms controls and the designer generated code that it is often easier to recreate a Windows.Forms class from scratch using the beta 1 file as a reference than it is to modify the beta 1 file to be compatible with beta 2.

 

 

June 07, 2005

Migrating from NUnit to Unit Test Framework in Visual Studio 2005 Beta 2

Visual Studio 2005 Beta 2 includes an integrated testing framework which includes, among other types of tests, support for unit tests.

It proved to be very simple to migrate NUnit based tests to this new framework.

Here are the changes that had to be made to individual test files:

NUnit Syntax

Visual Studio 2005 Syntax

using NUnit.Framework;

using Microsoft.VisualStudio.QualityTools.UnitTesting.Framework;

[TestFixture]

[TestClass]

[Test]

[TestMethod]

Assertion.AssertEqual

Assert.AreEqual

Assertion.Assert

Assert.IsTrue

 

The only hiccup I experienced was an unexplained “Invalid character in path” error dialog which appeared initially when trying to run the test project. The problem vanished after removing all the test files from the project and re-adding them one at a time.

 

May 03, 2005

DataGridView Validation

Windows Forms 2.0 has a new general purpose data display control called a DataGridView. It is intended to be easier to use and more powerful than the original DataGrid control.

The following experience may help you when it comes to adding data validation logic to a rather simple application of the DataGridView control.

An obvious (but WRONG) place to start is the CellValidating event of the DataGridView object. Here is a fairly reusable implementation of a CellValidating event delegate method:

 

    this.grid.CellValidating += new DataGridViewCellValidatingEventHandler(grid_CellValidating);

 

    void grid_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {

        DataGridViewCell cell = grid.Rows[e.RowIndex].Cells[e.ColumnIndex];

        TypeConverter tc = TypeDescriptor.GetConverter(cell.ValueType);

        try {

            object newValue = tc.ConvertFrom(e.FormattedValue);

            object oldValue = cell.Value;

            try {

                cell.Value = newValue;

            } finally {

                cell.Value = oldValue;

            }

        } catch (Exception ex) {

            grid.Rows[e.RowIndex].ErrorText = ex.Message;

            SystemSounds.Beep.Play();

            e.Cancel = true;

        }

    }

 

There are a few general things to point out about this method:

·        It uses a TypeConverter to determine if the new value (e.FormattedValue) can be converted to the type of value stored in the cell. Using a TypeConverter is a good general approach because FormattedValue isn’t always a string. It can, in theory, be just about any type.

·        It provisionally assigns the new value to the cell’s value to trigger any argument checking done by the underlying DataSource’s property setter. If there is a value range restriction on the data, you should be checking it at the first public interface level, not in some form specific UI code.

·        A finally block is used to restore the current value of the cell after the provisional assignment. There are several things not to like about this technique. The setter can have side effects (not good coding practice, but it happens). The setter can be resource intensive.

·        Validation errors result in exceptions being thrown. The exception’s message is set as the grid row’s ErrorText property and a beep sound is generated. The ErrorText property will cause a small error notification icon to appear in the row header with a tool tip set to the exception’s message.

·        The Validating event doesn’t happen when a value is simply assigned to a grid cell. For example if your paste-from-clipboard method attempts to assign the contents of the clipboard to a grid cell, you’ll have to implement separate validation logic there and validation failure notification logic.

When you use the ErrorText property, don’t forget to reset it after the problem has been fixed. The simplest way to do this is with the Validated event:

    this.grid.CellValidated += new DataGridViewCellEventHandler(grid_CellValidated);

 

    void grid_CellValidated(object sender, DataGridViewCellEventArgs e) {

        grid.Rows[e.RowIndex].ErrorText = String.Empty;

    }

 

The RIGHT place to put your validation logic is in the DataSource’s property setters, throw an ArgumentValueException for bad values, and use the DataError event instead of the CellValidating event to handle the exceptions:

    this.grid.DataError += new DataGridViewDataErrorEventHandler(grid_DataError);

 

    DateTime lastDataError = DateTime.MinValue;

    void grid_DataError(object sender, DataGridViewDataErrorEventArgs e) {

        e.Cancel = true;

        e.ThrowException = false;

 

        // A single error may cause secondary calls to this handler, ignore these.

        if (grid.Rows[e.RowIndex].ErrorText != String.Empty && null == e.Exception) return;

 

        TimeSpan sinceLast = DateTime.Now - lastDataError;

        lastDataError = DateTime.Now;

 

        string message;

        if (null == e.Exception)

            message = "Bad value.";

        else {

            message = e.Exception.Message;

            if (e.Exception is System.Reflection.TargetInvocationException)

                if (e.Exception.InnerException is FormatException)

                    message = "Bad value format. Check the type of value entered.";

        }

        grid.Rows[e.RowIndex].ErrorText = message;

        if (sinceLast.TotalSeconds < 1.0)

            MessageBox.Show(message + "\r\n\r\nPress Ctrl-Z to restore previous value.", "Bad Value");

        else

            SystemSounds.Beep.Play();

    }

 

The DataError event has a richer (more complicated) calling context than the CellValidating event, but this is a good thing. It allows you to be consistent and focused about your error handling and notification.

A few comments about the grid_DataError method:

·        The e.Context field of the event arguments is a DataGridViewDataErrorContext, which is a flags style enumerator that tells you the general context of the data error. You may want to specialize your handling based on the context in production situations.

·        In addition to the Cancel property there is a ThrowException property. Generally you can set these to true and false respectively because you’re going to handle the problem and take care of notifying the user.

·        A single error may cause a secondary call to the handler. This is the kind of thing that may get fixed by the time 2.0 goes into production. For now, ignore the second call by noticing that the exception property is null and an error message has already been set.

·        Many exception messages are fairly cryptic from an ordinary user’s perspective. Do whatever massaging is necessary for your application.

·        In addition to setting the ErrorText property for a small visual indicator of an error condition, either play a beep sound or, if this error followed the last by less than a second, put up a dialog to display the message directly and require the user to acknowledge it.

Hope this helps you…

 

 

 

April 05, 2005

Whidbey setup project race condition

Whidbey appears to suffer from an unhandled race condition when you “simultaneously” re-build a Windows Forms setup project and use the Add or Remove Programs control panel to remove the previously installed version.

Sometimes the build will fail with a missing file error in the installation folder. Sometimes the application will fail with an unregistered dependency.

 

December 08, 2004

Why does InvokeRequired return false when you'd like it to return true?

I’ve seen a number of developers surprised by InvokeRequired returning false in situations when they know it’s a cross thread call.

The reason is that the underlying window handle associated with the control has not been created yet at the time of the call.

Since InvokeRequired is meant to be used with either BeginInvoke or just Invoke, and neither of these methods can succeed until a windows message pump gets associated with the control, it elects to return false.

 

 

 

December 02, 2004

Whidbey FTP Support

There is some support for FTP in Whidbey beta 1, but it still failed my real world requirements.

Using both the FtpWebRequest / FtpWebResponse and WebClient classes failed to connect to an embedded system running an ftp server that Windows Explorer had no trouble connecting to.

I tried two third party FTP components for .NET (Mabry's FTP/NET and CSpot’s FTPComponent). Both components succeeded in connecting to the server when run as Visual Studio 2003 projects (using their own sample code). But both components failed (typically by hanging in the class constructors) when run after conversion to Visual Studio 2005 (Whidbey beta 1).

It seems that at the moment, there’s just enough FTP implementation in Whidbey to work with some FTP servers, but not all, and just enough changes to interfere with the existing crop of 3rd party components.

 

August 03, 2004

C# changes from 1.1 to 2.0

As of Beta 1.

C# 1.1 à 2.0

Generic classes, interfaces, and methods. Introduces the <type,argument,list> syntax.

Generic constraints. Introduces the syntax: “where T : (class_type | “class” | “struct” ,)? (interface_type | type_parameter ,)* (“new()”)?

Anonymous methods. Re-uses “delegate” and curly braces to declare and define inline methods.

Iterators. Methods that return IEnumerator or IEnumerable (or generic variants) may use “yield return” and “yield break” syntax within a loop to yield control on each item.

Partial types. Introduces “partial” syntax.

Nullable types. Introduces “int?” syntax for all value types and “??” operator.

 

 

Use using to alias long generic type names

Assigning a type name alias with a “using” directive in C# is a handy way to shorten a long type name and simplifies using generic types much as you would normally do with a typedef in C++.

namespace Foo {

            using Stack1 = Stack<Bar<int, string>>;

            … use Stack1 as a type alias for Stack<Bar<int, string>> …

}

 

July 30, 2004

Dynamically replacing controls, ViewState and PostData issues

For ViewState and PostData to work correctly when restoring state to the server controls during a POST to an ASP.NET aspx page, the UniqueID’s must be the same when state is restored as they were when state was saved..

I ran into trouble when I used a button’s click event handler to remove some controls and then added some replacement controls. The replacement controls were numbered sequentially starting after the original control numbering. When a postback occurred, my override of LoadViewState created only the replacement controls which were therefore numbered differently (since the original controls were never created). ViewState wasn’t being restored correctly and the checked property of CheckBox controls wasn’t being set correctly.

What’s missing from ASP.NET is a way of updating the naming scheme originated by the removed controls’ naming managers. If this were done, the replacement controls could be named consistently.

My workaround in this situation was to do a redirect back to the page with a query string argument that causes the correct new control layout to be created.

 

 

July 26, 2004

ICSharpCode.SharpZipLib access denied

To work around an access denied error in ASP.NET applications using ICSharpCode.SharpZipLib, register the assembly in the GAC.

There’s more to it. But for a quick fix this might solve your problem.

See also:

813833 - PRB: "Access Denied" Error Messages When You Do Not Put Strong-Named Assemblies in the Global Assembly Cache - http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b813833

 

 

July 05, 2004

Viewing a byte[] array contents in a Visual Studio memory window

I haven’t found a good source of tips yet on how to make effective use of Visual Studio’s memory windows when working with C# objects, so here’s one that may work to view the contents of a byte[] array:

1.      Open the memory window.

2.      Type the name of the array in the address box, this will show you the memory occupied by the System.Array object corresponding to your byte[] array.

3.      Enter the first four byte values you see, in reverse order with a “0x” prefix, in the address box.

4.      Ignore the first two bytes, or add 2 to the address entered in step 3.

 

 

June 17, 2004

Yeah! First post on a new overhauled dasBlog engine

From the start, I wasn’t as interested in a wildly popular blog as much as a reliable publicly accessible place to share the notes I’d been accumulating for a few years. And perhaps with Weblogs.com being unceremoniously shut down, reliability and self-determination aren’t so bad.

Anyone who’s reached the point in their blogging where they’re ready to move on to a new engine knows that preserving permalinks can dominate the equation. So, being a bit anally retentive, because I clearly don’t have the volume of high quality posts and user comments to justify it, I decided to invest in the future by making the URL scheme of all public site links a top priority of the move. After looking around a bit, here’s what I wanted to end up with:

Purpose

Public URL Scheme

default

 

login

login

logout

logout

search