Home > OS >  How i could resolve the async exception (freeze problem)
How i could resolve the async exception (freeze problem)

Time:09-16

I have an exception Must create DependencySource on same Thread as the DependencyObject

when i want to use ParallelForEachAsync:

    public async void TreeViewItem_Expanded(TreeView sender, RoutedEventArgs e)
    {
        var context = (e.OriginalSource as TreeViewItem).DataContext as ABrowser;
        //await LoadChildrenItemsAsync(context);
        await context.Children.ParallelForEachAsync(ProcessMessageAsync, Environment.ProcessorCount);

    }
    
    public  async Task ProcessMessageAsync(ABrowser i)
    {
        if (i.Children == null && i.IsNotFile && i.IsNotDrive)
        {
            i.Children = new BindableCollection<ABrowser>();

            var folders = Directory.EnumerateDirectories(i.Name);

            foreach (var folder in folders)
            {
                if ((File.GetAttributes(folder) & FileAttributes.Hidden) == FileAttributes.Hidden)
                    continue;
                i.Children.Add(new FolderTreeItemViewModel(this, i, folder));
                
            }

            var files = Directory.EnumerateFiles(i.Name, "*OpenClassrooms.htm");

            i.IsEnabled = files.Any();
            foreach (var file in files)
            {
                i.Children.Add(new FolderTreeItemViewModel(this, i, file, true));
            }
        }
        else
        {
            i.IsEnabled = true;
        }
        await Console.Out.WriteLineAsync($"Processing Message: {i.Name}");
    }
    
    

The problem is coming from binding Background Color (Backcolor) and binding Icon (freezable problem),

<StackPanel x:Name="toto" Orientation="Horizontal">
    <CheckBox  x:Name="IsSelected"  Margin="0 2 4 2" VerticalAlignment="Center"  IsEnabled="{Binding IsEnabled}"
               Visibility="{Binding Path=IsNotDrive, Converter={StaticResource BooleanToVisibilityConverter}}" Width="{Binding Size}" Height="{Binding Size}" Background="{Binding BackColor}"
               Style="{Binding StyleToUse}" materialDesign:ToggleButtonAssist.OnContent="{StaticResource CheckMarkIcon}" materialDesign:CheckBoxAssist.CheckBoxSize="{Binding Size}">
    </CheckBox>

    <Image Source="{Binding Icon}" VerticalAlignment="Center" Width="24" Height="24" Visibility="{Binding Path=IsNotFile, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    <TextBlock x:Name="Name" VerticalAlignment="Center" />

</StackPanel>    

I have tried to add Freeze(), but no success, or maybe i dont use that in right way..

I dont see how to resolve this problem...perhaps my async code is not correct...

Help will be welcome! i am using dotnet 4.8, Ninject, Caliburn ...

i have added a github link SampleCode

The code which uses BackColor:

   public abstract class ABrowser:PropertyChangedBase
    {
        public readonly SolidColorBrush Primary = (SolidColorBrush)Application.Current.Resources["PrimaryHueMidBrush"];
        public readonly SolidColorBrush Unselected = new SolidColorBrush(Colors.Red);
        public readonly SolidColorBrush Selected = new SolidColorBrush(Colors.ForestGreen);

        private SolidColorBrush backColor;
        public SolidColorBrush BackColor
        {
            get
            {
                return backColor;
            }

            set
            {
                if (backColor == value) return;
                backColor = value;

                NotifyOfPropertyChange(() => BackColor);
            }
        }
        
        
        private bool? isSelected;
        public bool? IsSelected
        {
            get => isSelected;
            set
            {
                if (isSelected == value) return;
                isSelected = value;

                if (!IsNotFile)
                {
                    BackColor = value == true ? Selected : Unselected;
                }
                else
                    BackColor = Primary;


                if (Children != null && value != null && IsNotFile && IsNotDrive)
                {
                    foreach (var i in Children)
                    {
                        if (i.IsNotFile) continue;
                        i.IsSelected = value;
                    }
                }
                else if(!IsNotFile && IsNotDrive)
                {
                    var (t, s) = NumberOfFilesSelected(this);

                    if (value == true && t - s > 0 || value == false && s > 0)
                    {
                        Parent.IsSelected = null;
                    }
                    else
                        Parent.IsSelected = value;
                }

                FirstParent.SomethingSelected = value == false ? FirstParent.GetAnySelected(FirstParent.Children) : true;

                NotifyOfPropertyChange(() => IsSelected);
                NotifyOfPropertyChange(() => BackColor);
            }
        }

CodePudding user response:

The exception is cleared by freezing the image source:

    using (System.Drawing.Icon i = System.Drawing.Icon.FromHandle(shinfo.hIcon))
    {
        //Convert icon to a Bitmap source
        shellIcon = Imaging.CreateBitmapSourceFromHIcon(
                                i.Handle,
                                new Int32Rect(0, 0, i.Width, i.Height),
                                BitmapSizeOptions.FromEmptyOptions());
        shellIcon.Freeze();
    }

The brush error is most likely due to the creation of an "ABrowser" instance in a thread other than the UI thread.
But it initializes the brushes fields: Primary, Unselected, Selected.
The brush is also a DependecyObject.
And if it is not frozen, then it can be used only by the thread in which it was created.

Try to make the fields static and freeze them:

    public abstract class ABrowser:PropertyChangedBase
    {
        public static readonly SolidColorBrush Primary = (SolidColorBrush)Application.Current.Resources["PrimaryHueMidBrush"];
        public static readonly SolidColorBrush Unselected = new SolidColorBrush(Colors.Red);
        public static readonly SolidColorBrush Selected = new SolidColorBrush(Colors.ForestGreen);

        static ABrowser()
        {
            Primary.Freeze();
            Unselected.Freeze();
            Selected.Freeze();
        }

P.S. The project was made with numerous architectural violations. In it, in general, it is difficult even to understand where the border between View, ViewModel and Model lies. The ViewModel does whatever comes to mind. In such an architecture (or rather, in its absence) there will still be numerous bugs, errors, exceptions.

  • Related