Search code examples
c#wpfxamlassociated-object

AssociatedObject.Content throws exception after a certain scope


I am attaching a behaviour for some usercontrols and when I add UI elements (Please see the IsEnable() method) it works fine. After a certain point when a notification comes, I want to update the Texblock that was added as content to the user control (Please see the LiveAnalysisIsDone() method). Problem is accessing CustomControlContent.Content throws an exception as "The calling thread cannot access this object as a different thread owns it". Please help.

public class UserControlLiveAnalysisBehaviour : System.Windows.Interactivity.Behavior<UserControl>
    {
        private TextBlock textBlock = new TextBlock();
        private UserControl CustomControlContent;

        private bool IsExecuted;
        protected override void OnAttached()
        {
            AssociatedObject.Loaded += UserControlLoadedHandler;
        }


        private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
        {
            RegisterUserControlActivatedHandler();
            Messenger.Default.Register<Notifications>(this,
                    (n) =>
                    {
                        if (n == Notifications.LiveAnalysisComplete)
                        {
                            LiveAnalysisIsDone();
                        }
                    });
        }

        public void LiveAnalysisIsDone()
        {
            string LiveAnalysisCompleteText = System.Windows.Application.Current.TryFindResource("LiveAnalysisComplete").ToString();
            if (CustomControlContent.Content != null)  //Exception here The calling thread cannot access this object as a different thread owns it
            {
                //Remove Children from UserControl
                if (CustomControlContent.GetType() != typeof(BioRad.ddPCR.UI.Views.Analysis.Reports.ReportGeneratorUserControl))
                {
                    //var childGrid = WPFUtils.FindChild<Grid>(CustomControlContent, "ContentGrid");
                    //var c = CustomControlContent.Content as Grid;
                    //Grid child = CustomControlContent.FindName("ContentGrid") as Grid;
                    //child.Children.Remove(child.FindName("SpTextPanel") as StackPanel);
                    ////Add new children
                    //StackPanel sp = new StackPanel();
                    //sp.HorizontalAlignment = HorizontalAlignment.Center;
                    //sp.VerticalAlignment = VerticalAlignment.Center;
                    //sp.Children.Add(new TextBlock { Text = System.Windows.Application.Current.TryFindResource("LiveAnalysisComplete").ToString(), Foreground = new SolidColorBrush(TextBlockStyle()), Effect = null, HorizontalAlignment = HorizontalAlignment.Center, TextAlignment = TextAlignment.Center, FontWeight = FontWeights.SemiBold });
                    //sp.Effect = null;
                    //child.Children.Add(sp);
                    textBlock.Text = System.Windows.Application.Current.TryFindResource("LiveAnalysisComplete").ToString();

                }
            }
        }

        private void RegisterUserControlActivatedHandler()
        {
            CustomControlContent = AssociatedObject;
            if (CustomControlContent == null)
            {
                return;
            }

            var RunDataInstance = RunDataViewModel.Instance;
            RunDataViewModel.RunDataFileSession<string> session = RunDataInstance.GetLiveSessionObject();
            if (session != null)
            {
                if (session.IsLiveAnalysisSession && !IsExecuted)
                {
                    if (CustomControlContent.GetType() == typeof(BioRad.ddPCR.UI.Views.Analysis.Reports.ReportGeneratorUserControl))
                    {
                        var child = CustomControlContent.FindName("btnGenerateReport") as Button;
                        if (child != null)
                        {
                            child.IsEnabled = false;
                            IsExecuted = true;
                            return;
                        }
                    }
                    textBlock.Text = System.Windows.Application.Current.TryFindResource("LiveAnalysisInProgress").ToString();
                    IsEnabled(); 
                }
            }
        }

        private void IsEnabled()
        {
            Grid grid = new Grid();
            grid.Name = "ContentGrid";
            RowDefinition r1 = new RowDefinition();
            r1.Height = new GridLength(30, GridUnitType.Auto);
            grid.RowDefinitions.Add(r1);
            RowDefinition r2 = new RowDefinition();
            r2.Height = new GridLength(30, GridUnitType.Auto);
            grid.RowDefinitions.Add(r2);
            ContentControl cc = new ContentControl();
            StackPanel Sp = new StackPanel();
            Sp.Name = "SpTextPanel";
            Sp.HorizontalAlignment = HorizontalAlignment.Center;
            Sp.VerticalAlignment = VerticalAlignment.Center;
            Panel.SetZIndex(Sp, 1000);
            Sp.Children.Add(new TextBlock { Text = textBlock.Text, Foreground = new SolidColorBrush(TextBlockStyle()), Effect = null, HorizontalAlignment = HorizontalAlignment.Center, TextAlignment = TextAlignment.Center, FontWeight = FontWeights.SemiBold });
            Sp.Background = Brushes.Transparent;
            BlurEffect effect = new BlurEffect();
            effect.Radius = 7;
            (CustomControlContent.Content as UIElement).Effect = effect;
            Grid.SetRowSpan(cc, 2);
            Sp.Effect = null;
            cc.Content = CustomControlContent.Content;
            Grid.SetRow(Sp, 0);
            grid.Children.Add(cc);
            grid.Children.Add(Sp);
            CustomControlContent.Content = grid;
            IsExecuted = true;
        }

        public Color TextBlockStyle()
        {
            if (Brushes.White.Equals(CustomControlContent.Background) || Brushes.WhiteSmoke.Equals(CustomControlContent.Background))
            {
                return Colors.Gray;
            }
            else
            {
                return Colors.White;
            }
        }

    }

Solution

  • Ok as other posts suggests The calling thread cannot access this object because a different thread owns it I am using a Dispatcher and it works just fine. Here is the place where I am using a Dispatcher to update the progress.

    public void LiveAnalysisIsDone()
            {
                string LiveAnalysisCompleteText = System.Windows.Application.Current.TryFindResource("LiveAnalysisComplete").ToString();
                if (CustomControlContent != null)               {
                    //Remove Children from UserControl
                    if (CustomControlContent.GetType() != typeof(BioRad.ddPCR.UI.Views.Analysis.Reports.ReportGeneratorUserControl))
                    {
                        this.Dispatcher.BeginInvoke((Action)(() =>
                        {
                            var content = CustomControlContent.Content as Grid;
                            if (content != null)
                            {
                                var Panel = content.Children[1] as StackPanel;
                                (Panel.Children[0] as TextBlock).Text = LiveAnalysisCompleteText;
                            }
                        }));
    
    
                    }
                }
            }