gpt4 book ai didi

c# - 调用 UI 更新时出现异常

转载 作者:行者123 更新时间:2023-11-30 14:52:08 25 4
gpt4 key购买 nike

我也是 C#、WPF 和线程的新手。我正在使用 MVC5 开发 Web 应用程序。

我了解到,在主线程以外的线程中更新 UI 元素时,我应该调用调度程序。但我并没有完全了解我需要做的改变。

我有一个 GetBitmapForDistributionChart 方法,它可以像这样更新 UI。

public byte[] GetBitmapForDistributionChart(int width, int height, DistributionChartParameters disrtibutionParams)
{
// delegate control instantiation to STA Thread
return DelegateBitmapGenerationToSTAThread(() =>
{
Chart canvasChart = new Chart(languageService);
canvasChart.Width = width;
canvasChart.Height = height;

canvasChart.Measure(new Size(width, height));
canvasChart.Arrange(new Rect(0, 0, width, height));

return GenerateBitmapFromControl(canvasChart, width, height);
});
}

DelegateBitmapGenerationToSTAThread 的定义如下所示:

private byte[] DelegateBitmapGenerationToSTAThread(Func<byte[]> controlBitmapGenerator)
{
byte[] imageBinaryData = null;

Thread thread = new Thread(() =>
{
var renderer = new BitmapCreator(this.languageService);
imageBinaryData = controlBitmapGenerator();
});

//Set the thread to STA
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

//Wait for the thread to end
thread.Join();

return imageBinaryData;
}

我得到一个异常“不能使用与其父 Freezable 属于不同线程的 DependencyObject。”在 canvasChart.Arrange 当我在图表类中添加以下行时:

rect.Fill = distributionParams.rangeData.ElementAt(i).barColor;

在主线程中。

如果我将同一行更改为不依赖于右侧类的内容,那么它就可以工作。

Like, rect.Fill = new SolidColorBrush(Colors.Red);

我不知道如何解决这个问题。

注意:我也得到异常“调用线程无法访问此对象,因为另一个线程拥有它。”尝试这样做时:

rect.Fill = new SolidColorBrush(distributionParams.rangeData.ElementAt(i).barColor.Color);

distributionParams 结构如下所示:

public struct DistributionParams
{
public struct RangeData
{
public string range;
public double distributionValue;
public SolidColorBrush barColor;
}
public List<RangeData> rangeData;
}

请帮我解决这个问题。

最佳答案

因此,在 DelegateBitmapGenerationToSTAThread 中您启动新的 STA 线程。然后您尝试在那里访问 DistributionParams.RangeData.barColor,它是 SolidColorBrush 类型。您在另一个(主 UI)线程中创建这些画笔,这就是您收到此异常的原因。你可以做些什么来解决这个问题:

  1. 尝试在创建后卡住画笔。

    d.barColor = new SolidColorBrush(...);
    d.barColor.Freeze();
  2. 使用预定义的画笔,它们已经卡住:

    d.barColor = Brushes.Blue;
  3. 使用颜色代替 SolidColorBrush

    d.barColor = Colors.Blue;

然后,在必要时创建 SolidColorBrush

 rect.Fill = new SolidColorBrush(d.barColor);

更新以回答您评论中的问题。SolidColorBrush 可能看起来无辜,但它仍然是与 UI 相关的对象,它定义了界面将如何呈现。 WPF(和 WinForms)中的此类对象具有线程亲和性 - 它们可能只能由一个线程(创建它们的线程)访问。为什么会有这样的限制?因为要正确有效地对影响呈现的此类元素的属性实现并发更改 并不容易。在 SolidColorBrush 的情况下,想象 10 个线程改变它的颜色,并且 UI 线程尝试渲染所有这些。所以因为允许更改 - 读取也不安全。

现在,如果您的类继承自 Freezable,WPF 会以特殊方式对其进行处理。如果它是 Freezable 和 frozen,类作者保证对象不能再被更改(将在任何更改或其他情况下抛出异常)。然后从任何线程访问此类对象都是安全的,即使此对象与 UI 相关。

回到 SolidColorBrush。当您创建它(使用任何颜色,甚至是预定义的颜色)时,默认情况下它不会被卡住,您可以随时更改其 Color 属性。如果您使用预定义的画笔(例如 Brushes.Red)- 它已经为您卡住,您不能执行 Brushes.Red.Color = Colors.Blue。

关于c# - 调用 UI 更新时出现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32476014/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com