【问题标题】:Using a BackgroundWorker to call a serialization method使用 BackgroundWorker 调用序列化方法
【发布时间】:2016-12-08 16:04:17
【问题描述】:

我遇到了一个我不知道如何解决的问题,所以我开始认为我没有正确理解 BackgroundWorker。

我正在尝试使用 BackgroundWorker 来处理程序中的保存/加载功能,这意味着我希望工作人员调用我创建的序列化方法。

序列化方法采用 POCO 并 xml 序列化它。此 POCO 包含多个属性,其中之一是 Brush 类型。

public Brush ShapeColor{ get; set; }

我想序列化颜色,但由于无法序列化画笔,所以我做了一个辅助属性:

public Color StoreColor
{
    get
    {          
         g = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).G;
         r = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).R;
         b = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).B;           
         return Color.FromRgb(r, g, b);
    }
    set {}
}

不使用BackgroundWorker 也能正常工作。 但是一旦我尝试在doWork 方法中对序列化方法进行方法调用,就会抛出异常:

调用线程无法访问此对象,因为另一个线程拥有它。

关于这些:

g = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).G;
r = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).R;
b = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).B;   

我的理解是,通过使用BackgroundWorker 从另一个线程而不是 UI 线程调用序列化方法,我违反了工作人员无法访问 UI 元素的规则。

老实说,我不太清楚如何提出我的问题,但我不可能只从工人那里序列化这些 POCO 吗?和ShapeColor是刷子有关系吗?

提前感谢我的错误解释:)

编辑:发布 xml 序列化方法。

public static void convertToXML<T>(T objectToSave, string path) where T : new()
    {
        StreamWriter streamWriter = null;
        try
        {               
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            streamWriter = new StreamWriter(path, false);             

            XmlWriterSettings settings = new XmlWriterSettings()
            {
                Indent = true,
                OmitXmlDeclaration = true,
            };
            serializer.Serialize(streamWriter, objectToSave);

        }
        finally
        {
            // Close writer
            if (streamWriter != null)
            {
                streamWriter.Close();
            }
        }
    }

【问题讨论】:

  • 在创建ShapeColor 以及在此处访问它时尝试检查Thread.CurrentThread.ManagedThreadId
  • GDI 对象(如画笔)不仅仅是数据结构,它们与 UI 线程相关联。您不能并且不需要为此使用BGW。 BGW 已被弃用并且对于异步保存完全没有必要。您可以使用例如FileStream的异步方法来异步保存数据
  • 请张贴您的序列化代码。您发布的代码不会导致问题,也无法修改以修复它
  • @PanagiotisKanavos 所以是的,我读了一些,发现听起来你有我的答案:) - 我将能够修改序列化代码以实现异步调用,因为 StreamWriter API 支持异步方法?然后就放弃整个 BGW 的想法 :)?所以每次我序列化某些东西时,序列化方法会负责在另一个线程中处理任务?
  • 这是一个非常具体的 WPF 限制。有点笨拙,但它对扩展属性的线程安全采取了严肃的态度。您对此无能为力,您需要先在 UI 线程上准备好数据,然后再让工作线程保存它。不会让代码更漂亮。

标签: c# multithreading serialization backgroundworker


【解决方案1】:

您遇到了Freezable 对象。

这些对象通常只能在创建它们的线程(在您的情况下是 Dispatcher 线程)中以 Unfrozen 状态处理。

为了在另一个线程上处理它们(而不是操纵它们),您需要Freeze() 它们然后将它们交给另一个线程,或者使用Dispatcher.Invoke()Dispatcher 线程上进行调用。

int r =0;
int g =0;
int b =0;
//Marshalls back to UI thread
Dispatcher.Invoke(()=>{
 r = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).R;
 g = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).G;
 b = ((Color)ShapeColor.GetValue(SolidColorBrush.ColorProperty)).B;
});
//Creates object on BGW thread and can be safely used for serialization
return Color.FromRgb(r, g, b);

【讨论】:

  • 所以我尝试了你的解决方案:)!尽管我必须改用“Application.Current.Dispatcher.Invoke ..”。不知道这样行不行?
  • 这是可以的,因为通常每个应用程序只有一个 Dispatcher。您可以拥有多个 Dispatcher,但这是一项非常专业、高级的工作。请记得标记为答案。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多