Changing the DataContext before a control is loaded will not work

Since some time, I am working on Catel, and open-source enterprise library with a MVVM-framework. One of the user controls that is developed for Catel is a generic UserControl that solves the nested controls problem of MVVM.

However, for this to work, I needed to change the DataContext, and what better event to use than the DataContextChanged event. However, when the control was loaded, the DataContext was set to the right type (the view model), but the bindings were still trying to bind to the model instead of the view model.

Desperately as I was, I posted this on the MSDN forums. But, too badly, no-one could help me out, so I decided to have a dream that explained to me that I had to walk around the house 3 times during full moon.

Then I thought: hey, the control is not yet loaded, maybe I should try to change the data context after I the control is loaded. And, this seems to solve the problem. You will get binding errors once (since at the initial load, the bindings are still trying to bind to the model), but after you set the datacontext to the viewmodel, all works like a charm.

So, keep in mind: you can only change the datacontext of a control when IsLoaded is true.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Managing application resources when WPF is hosted

Recently, I was working on a project that had WPF controls and windows hosted in Windows Media Player. When using WPF styles correctly (themes, resources, etc), normally one would create a resource library with all the styles.

When WPF is hosted, no System.Windows.Application.Current is available, so no application resources are available. Because of this, every window and control has to load the main theme resource dictionary on each load. This isn’t exactly what one would like to do. After searching for a while, I found this interesting article of Dr. WPF. It’s a long article, but the most interested part is to create the current application object yourself:

public static void EnsureApplicationResources()
{
    if (Application.Current == null)
    {
        // create the Application object
        new Application();

        // merge in your application resources
        Application.Current.Resources.MergedDictionaries.Add(
            Application.LoadComponent(
                new Uri("MyLibrary;component/Resources/MyResourceDictionary.xaml",
                UriKind.Relative)) as ResourceDictionary);
    }
}

At first, this seemed to work great in my scenario. However, when a window was shown the 2nd time, the application (in my case, Windows Media Player) crashed. After some investigation, I noticed that the application was not valid anymore after the the first window was shown. This brought me to the idea that the first window that is created is automatically set to the main window of the application. As soon as that window closes, the application gets destroyed. However, I don’t have a main window, I can only show windows as popups, not as main window of the application.

Hereby, I present to you as a reader of my blog, the solution to this issue. Create the first “main application window” yourself and make sure that it is invisible. This window will stay in scope (since Application.Current.MainWindow has a reference) as long as the hosting application is running. The following code should be used instead of the one that Dr. WPF has posted:

/// 
/// Ensures that an application instance exists and the styles are applied to the application.
/// 
public static void EnsureApplicationResources()
{
	// Do we have an application?
	if (Application.Current == null)
	{
		// Create the Application object
		new Application();

		// merge in your application resources
		Application.Current.Resources.MergedDictionaries.Add(Application.LoadComponent(new Uri("/MyLibrary;component/Themes/Generic.xaml", 
			UriKind.RelativeOrAbsolute)) as ResourceDictionary);

		// Create style forwarders
		CatenaLogic.Windows.StyleHelper.CreateStyleForwardersForDefaultStyles(Application.Current.Resources);

		// Create an invisible dummy window to make sure that this is the main window
		Window dummyMainWindow = new Window();
		dummyMainWindow.Visibility = Visibility.Hidden;
	}
}

As you might have noticed, a StyleHelper is used. This is another article, you can find it here.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Context sensitive help for Windows Forms – part 2

This is an update to the old version of the CatenaLogic.Help namespace.

How to use

  1. Recompile the library from the provided source
  2. Put the HelpComponent on the main form of your application
  3. Run the application with helpprovider commandline parameter
  4. Use Ctrl+F1 to map help topics to controls. Remember about the hierarchy - you do not have to provide topics for all controls, it is sufficient to provide the topic for a container control and all its child controls inherit the mapping.
  5. Remember to provide a help file name (must be a *.chm file located beside the application main executable)
  6. When the mapping is complete, include the help.mapping file stored beside the application main executable as an embedded resource in one of assemblies
  7. Remove the help.mapping file located beside the application main executable
  8. Rebuild the application

Screenshot

help_editor Use of the Help Editor in a real-world application

History

(*) Help file now correctly handles empty keywords (so it is actually possible to remove topics)
(*) Refactored code

Download

CatenaLogic.Help.zip (30.03 kb) [Downloads: 56]

kick it on DotNetKicks.com

 

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Log4net TraceListener

Until now, I used the static Trace class to log information of applications to a log file. However, recently a collegue recommended log4net since it supports formatting options of the log file and to set the maximum filesize of the logfile (the logfiles we received were very big). Also, it supports a lot of trace helper methods I wrote to trace exceptions with information.

However, the whole application has tracecs, and I didn’t want to change all of the calls just for the log4net change. Therefore, I wrote the Log4netTraceListener class to forward all traces to log4net.

This is how to use the class:

1) Add the file to your application or core library if you prefer that.

2) Add the trace listener to the app.config file:

<!-- Diagnostics settings -->
<system.diagnostics>    
    <!-- All your other options here -->
    <trace autoflush="true">   
      <listeners>    
        <add name="Log4netTraceListener" type="CatenaLogic.Diagnostics.Log4netTraceListener, MyAssembly" />
      </listeners>  
    </trace>
</system.diagnostics>

Log4netTraceListener.cs (6.62 kb) [Downloads: 81]

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

First chance exceptions in C++ UI classes

Recently, I was developing a CPropertySheet based application (the application development started in VS 6, but is now done in VS 2010). I got some "first-chance-exceptions" in the SetActivePage method of the PropertySheet.

The documentation of the SetActivePage method already warns about the first chance exceptions that you might get, but in my case, that didn't help solve the exceptions.

After some digging, I noticed that the font of the property pages was not consistent. Older objects had either "MS Sans Serif" or "MS Shell". However, all pages should have "Microsoft Sans Serif".

After changing the fonts of all dialog resources, all exceptions are now history.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList