The company for which I'm consulting has a specific business requirement that each instance of certain WPF Windows MUST have their own UI Thread and NOT share the default UI thread created by .NET Framework when the application is first loaded.
From a coding perspective, this is easy to accomplish and works well, until introducing the Telerik RadDocking control in the xaml. I have copied and pasted the xaml form telerik's RadDocking example directly from the sample code without modifying it. When the app launches, both instances of WindowWithTelerikDockingFromExample [seemingly] load without issue at first, in fact, the second instance of the window (titled "Window on seperate UI Thread...") is operational and works, as does "MainWindow". It's not until you activate the second window and then activate the main window, and then switch back to the second window that the following exception is thrown:
"The calling thread cannot access this object because a different thread owns it."
Locating source for
'c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs'. Checksum: MD5 {3e 1e cd 2a 97 89 30 7e c9 1c 28 c2 28 13 aa e9}
The file 'c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs' does not exist.
Looking in script documents for 'c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs'...
Looking in the projects for 'c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs'.
The file was not found in a project.
Looking in directory 'C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\src\atl\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\include\'...
The debug source files settings for the active solution indicate that the debugger will not ask the user to find the file: c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs.
The debugger could not locate the source file 'c:\TB\117\WPF_Scrum\Release_WPF\Sources\Development\Controls\Docking\Docking\Parts\AutoHideArea.cs'.
Here is my code:
App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
this.ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose;
// Init the application's main window...
var mainWindow = new WindowWithTelerikDockingFromExample();
mainWindow.Title = "Main Window";
this.MainWindow = mainWindow;
mainWindow.Show();
// init another instance of the window with the telerik docking, on a seperate UI thread...
var thread = new Thread(() =>
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
var window2 = new WindowWithTelerikDockingFromExample();
window2.Title = "Window on seperate UI Thread...";
window2.Show();
System.Windows.Threading.Dispatcher.Run();
window2.Closed += (s2, e2) =>
{
window2.Dispatcher.InvokeShutdown();
};
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
base.OnStartup(e);
}
}
WindowWithTelerikDockingFromExample.xaml:
<Window x:Class="TelerikDockingThreadIssueExample.WindowWithTelerikDockingFromExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="Window with xaml copy and pasted from Telerik example" Height="300" Width="300">
<Grid>
<telerik:RadDocking BorderThickness="0" Padding="0">
<telerik:RadDocking.DocumentHost>
<telerik:RadSplitContainer>
<telerik:RadPaneGroup>
<telerik:RadDocumentPane Header="Document 1" Title="Document 1" />
</telerik:RadPaneGroup>
</telerik:RadSplitContainer>
</telerik:RadDocking.DocumentHost>
<telerik:RadSplitContainer InitialPosition="DockedLeft">
<telerik:RadPaneGroup>
<telerik:RadPane Header="Pane Left 1" IsPinned="False">
<TextBlock Text="Pane Left 1" />
</telerik:RadPane>
<telerik:RadPane Header="Pane Left 2" IsPinned="False">
<TextBlock Text="Pane Left 2" />
</telerik:RadPane>
<telerik:RadPane Header="Pane Left 3" IsPinned="False">
<TextBlock Text="Pane Left 3" />
</telerik:RadPane>
<telerik:RadPane Header="Pane Left 4" IsPinned="False">
<TextBlock Text="Pane Left 4" />
</telerik:RadPane>
</telerik:RadPaneGroup>
</telerik:RadSplitContainer>
<telerik:RadSplitContainer InitialPosition="DockedRight">
<telerik:RadPaneGroup>
<telerik:RadPane Header="Pane Right 1" IsPinned="False">
<TextBlock Text="Pane Right 1" />
</telerik:RadPane>
</telerik:RadPaneGroup>
</telerik:RadSplitContainer>
<telerik:RadSplitContainer InitialPosition="DockedBottom">
<telerik:RadPaneGroup>
<telerik:RadPane Header="Pane Bottom 1" IsPinned="False">
<TextBlock Text="Pane Bottom 1" />
</telerik:RadPane>
</telerik:RadPaneGroup>
</telerik:RadSplitContainer>
</telerik:RadDocking>
</Grid>
</Window>
Any ideas?
Since the company is a paying customer of Telerik, I was able to use their account to send information to Telerik via a support ticket. The following an excerpt of what I sent them. It's somewhat similar to the question I originally posted on StackOverflow, however, I took it a step further and decompiled their RadDocking DLL and made a suggestion on what they need to do to fix this issue. I'm happy to report that they responded to the question:
We have a specific business requirement that specific instances of WPF Windows must each have their own UI thread, as opposed to using the default UI thread that is created with the application is loaded. From our experience doing so has been relatively easy to accomplish from a coding perspective, until we introduce the Telerik RadDocking control into the mix. I have attached a zip file containing simple VS Solution with two main files. One of them is the app.xaml.cs and the other is a Window called WindowWithTelerikDockingFromExample.xaml. The the xaml in the Window was directly copied and pasted from your WPF Docking example, with no changes. The app.xaml.cs file has one method: OnStartup. The OnStartup method does two things: 1. It first creates an instance of Window and sets the application MainWindow to that instance. 2. It then creates another instance of the Window, but under a different thread. Two instances of the Window launch without issue and are operational. It's not until the user activates one of them, and then activates the other, and then activates the other again when the following exception is thrown: "The calling thread cannot access this object because a different thread owns it."
We believe the problem lies somewhere within the AutoHideArea class in the Telerik.Windows.Controls.Docking.dll. We took it upon ourselves to use your free Telerik JustDecompile tool to decompile theTelerik.Windows.Controls.Docking.dll in attempt to help investigate where the issue might be occurring. The "OnLoaded" method in AutoHideArea wires an "OnApplicationDeactivated" event like so:
If you follow the OnApplicationDeactivated method you'll notice it calls an "area.CloseImmediately()" method, like so:
If you follow that method all the way through, you'll notice it sets the base.SelectedIndex = -1, like so:
We suggest changing the method to look something like the following:
The following is Telerik's response: