Within each thread, a new window is created, with a RadDocing, RadSplitContainer, RadPaneGroup and a single RadPane. The window is then displayed. When you click on the PaneHeader in any window other than the first thread that is opened, the application immediately throws a threading exception: System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
This exception occurs even when we have no code other than starting the threads. Has anyone else had this problem? Is there any way to fix this problem?
Thanks,
Daniel
6 Answers, 1 is accepted
Could you please share your code, on how you created multiple rad docking panes on multiple threads? I am trying to do the same but I cannot find my way around it.
It would be great help if you could.
Thanks
I created a small test application that creates windows in different threads, each with their own rad docking pane in the window.
First I set up a window with a button on it that would execute a command to start a new thread
<Window x:Class="DockingTest.MainWindow" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" Title="MainWindow" Height="60" Width="100"> <Grid> <telerik:RadButton Content="Start Thread" Command="{Binding Path=StartThread}"/> </Grid></Window>This is all bound to the MainWindowViewModel which executes the StartThread command.
public class MainWindowViewModel{ public ICommand StartThread { get; set; } public MainWindowViewModel() { StartThread = new RelayCommand(StartDockingInNewThread); } private void startNextThread() { System.Windows.Window w = new System.Windows.Window() { Height = 300, Width = 300 }; try { DockingView pv = new DockingView(); w.Content = pv; w.Show(); Dispatcher.Run(); } catch(Exception e) { } finally { var dispatcher = w.Dispatcher; if (!dispatcher.HasShutdownStarted) { dispatcher.InvokeShutdown(); } } } private void StartDockingInNewThread() { Thread thread = new Thread(new ParameterizedThreadStart( new Action<object>((o) => { startNextThread(); }))); thread.SetApartmentState(ApartmentState.STA); thread.Start(new object()); Thread.Sleep(1); }}
The method StartDockingInNewThread() creates the new thread, and starts it.
When startNextThread() executes, it creates the new window, adds the contents of the window, displays it and then invokes Dispatcher.Run() to cause the thread to start listening for events.
The DockingView is a UserControl that contains a rad docking pane
<UserControl x:Class="DockingTest.DockingView" xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:DockingTest="clr-namespace:DockingTest" mc:Ignorable="d" > <Grid> <telerikDocking:RadDocking HasDocumentHost="False" x:Name="_docking"> <telerikDocking:RadSplitContainer InitialPosition="DockedLeft" Orientation="Vertical" x:Name="_splitLeft"> <telerikDocking:RadPaneGroup x:Name="_group" telerikDocking:ProportionalStackPanel.RelativeSize="1, 2" AllowDragReorder="True" AllowDragOverTab="True"> <telerikDocking:RadPane x:Name="_pane" Header="Invintory" CanUserClose="True" IsSelected="True"> <TextBlock Text="This is some Text"/> </telerikDocking:RadPane> </telerikDocking:RadPaneGroup> </telerikDocking:RadSplitContainer> </telerikDocking:RadDocking> </Grid></UserControl>Under normal, non-threading circuimstances this works as expected. However, when opening up multiple threads with RadDocking, only the first thread opened will work as expected. In order to fix this problem, the style used for the PaneHeader needs to be overwritten.
I created a Resource Dictionary to overwrite this style
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"> <!--PaneHeader Style--> <Style x:Key="PaneHeaderStyle" TargetType="telerik:PaneHeader"> <Setter Property="telerik:InputBindingsManager.InputBindings"> <Setter.Value> <InputBindingCollection> <MouseBinding Command="telerik:RadDockingCommands.PaneHeaderMenuOpen"> <MouseBinding.Gesture> <MouseGesture MouseAction="RightClick" /> </MouseBinding.Gesture> </MouseBinding> </InputBindingCollection> </Setter.Value> </Setter> </Style> <!--Set the style--> <Style TargetType="telerik:PaneHeader" BasedOn="{StaticResource PaneHeaderStyle}" /></ResourceDictionary>Once you create the Resource Dictionary, then you need to use it in the DockingView by adding it to your UserControl.Resources in the xaml
<UserControl.Resources> <ResourceDictionary Source="Dictionary1.xaml"/></UserControl.Resources>After adding this resource dictionary to redefine the input bindings, you can run multple threads without them crashing.
I hope this helps,
Daniel
Thanks in advance.
Danny
You could find a lot of information about how to implement a multi UI thread on net, for example:
- http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/
- http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
- http://msdn.microsoft.com/en-us/library/ms741870.aspx
- http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx
You could run RadDocking in a separate Window using the follow code:
private void Button_Click_1(object sender, RoutedEventArgs e) { Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); newWindowThread.SetApartmentState(ApartmentState.STA); newWindowThread.Start(); } private void ThreadStartingPoint() { var tempWindow = new DockingView(); tempWindow.Show(); System.Windows.Threading.Dispatcher.Run(); }The RadDocking control is placed into the DockingView which inherits Window. Anyway, please note that the RadDocking is not design to run in different thread and there could be some unexpected problems.
Regards,
George
Telerik
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.