必须在与 DependencyObject 相同的线程上创建 DependencySource [英] Must create DependencySource on same Thread as DependencyObject

查看:28
本文介绍了必须在与 DependencyObject 相同的线程上创建 DependencySource的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用 wpf 编写的应用程序,它下载一些网页,解析 html 代码并保存一些值.

I have an application written in wpf, which downloads some webpages, parses html code and saves some values.

class ListOfItems
{    
    public List<SomeObject> ListToBind;
    public void DownloadItems()
    { 
        Task.Factory.StartNew(() => 
        {
            ...
            ...
            if (OnDownloadCompleted != null)
                OnDownloadCompleted(this, EventArgs.Empty);
        }
    }
}

class SomeObject
{
    public string NameOfItem;
    public MyClass Properties;
}

class MyClass
{
    public int Percentage;
    public SolidColorBrush Color;
}

这是我使用的对象模型.它是简化版,我不想让你重新组织它,我这样写是有原因的.在 ListOfItems 类中是完成所有工作的方法(内部还有一些其他方法用于使代码可读) - 下载源代码,解析并用数据填充 ListToBind,fe

This is the object model I'm using. It's simplified version and I don't want you to reorganize it, there is a reason I wrote it this way. In ListOfItems class is method which does all the job (there are some other methods used inside to make code readable) - downloads source, parses and fills ListToBind with data, f.e.

[0] => NameOfItem = "FirstOne", Properties = {99, #FF00FF00}
[1] => NameOfItem = "SecondOne", Properties = {50, #FFFF0000}
etc.

如您所见,当此方法 DownloadItems 完成其工作时,会引发 OnDownloadCompleted 事件.在主线程中是以下代码

As you can see, when this method DownloadItems completes its job, OnDownloadCompleted event is raised. In the main thread is following code

void listOfItems_OnDownloadCompleted(object sender, EventArgs args)
{
    dataGrid.Dispatcher.Invoke(new Action(() => { 
                dataGrid.ItemsSource = ListOfItemsInstance.ListToBind;
            }));
}

MainWindow.xaml 上的 DataGrid 填充了值,因为以下 xaml 代码片段.

DataGrid on the MainWindow.xaml is filled with values, because of following xaml code snippet.

<DataGrid Name="dataGrid" AutoGenerateColumns="False">
    <DataGrid.Columns>
         <DataGridTextColumn Header="Tag" Binding="{Binding Name}"/>
         <DataGridTextColumn Header="Color" Binding="{Binding MyClass.Percentage}">
             <!--<DataGridTextColumn.CellStyle>
                 <Style TargetType="DataGridCell">
                     <Setter Property="Background" Value="{Binding MyClass.Color}" />
                 </Style>
             </DataGridTextColumn.CellStyle>-->
         </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

它工作得很好.但是有这个问题.尝试取消注释已注释的 xaml 片段,您将收到 Must create DependencySource on the same Thread as the DependencyObject. 错误.

It works just fine. But there is this problem. Try to uncomment commented xaml snippet and you will get Must create DependencySource on same Thread as the DependencyObject. error.

最后,我的问题是,如何避免这个错误?

Finally, my question is, how to avoid this error?

最后应该是这个样子.这张图片来自 MS Excel,并在 Adob​​e Photoshop 中着色.

It should look like this in the end. This picture is taken from MS Excel and coloured in Adobe Photoshop.

推荐答案

SolidColorBrush 是一个 Freezable,它是派生的 DispatcherObject.DispatcherObjects 具有线程关联性 - 即它只能在创建它的线程上使用/交互.然而,Freezables 确实提供了冻结实例的能力.这将阻止对对象的任何进一步更改,但它也会释放线程关联.因此,您可以更改它,以便您的属性不存储像 SolidColorBrush 这样的 DependencyObject,而只存储颜色.或者,您可以使用 冻结 方法冻结正在创建的 SolidColorBrush.

The SolidColorBrush is a Freezable which is a derived DispatcherObject. DispatcherObjects have thread affinity - i.e it can only be used/interacted with on the thread on which it was created. Freezables however do offer the ability to freeze an instance. This will prevent any further changes to the object but it will also release the thread affinity. So you can either change it so that your property is not storing a DependencyObject like SolidColorBrush and instead just store the Color. Or you can freeze the SolidColorBrush that you are creating using the Freeze method.

这篇关于必须在与 DependencyObject 相同的线程上创建 DependencySource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆