使用Parallel.Foreach或IEnumerable.AsParallel()。ForAll()或Threads更新Canvas的内容时遇到一些麻烦。
我在画布中有很多行,当用户调整窗口大小时,我需要将它们的坐标相关更改为Canvas的新大小。
我把我的行放在
中 IEnumerable<Line> lineCollection = canvas.Children.OfType<Line>();
然后我尝试使用Parallel.Foreach或IEnumerable.AsParallel()来并行循环它们.ForAll()
在这种情况下我收到了AggregateException。它说,调用线程无法访问此对象,因为主线程拥有它。
我如何用我的UIElements做到这一点。
这是我的代码:
private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
Double hDelta = e.NewSize.Height / e.PreviousSize.Height;
if (Double.IsInfinity(hDelta)) return;
IEnumerable<Line> LineCollection = canvas.Children.OfType<Line>();
try
{
Parallel.ForEach(LineCollection, (line) =>
{
Double topProp = (Double)line.GetValue(Canvas.TopProperty) * hDelta;
line.SetValue(Canvas.TopProperty, topProp);
});
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is Exception)
{
MessageBox.Show(x.ToString(), "error");
}
return false;
});
}
}
我在这一行收到错误:
line.SetValue(Canvas.TopProperty, topProp);
答案 0 :(得分:0)
这解决了我的问题。
Line[] keysLineCollection = YAxisKeys.Children.OfType<Line>().ToArray();
Label[] keysLabelCollection = YAxisKeys.Children.OfType<Label>().ToArray();
try
{
new Thread(delegate ()
{
Parallel.ForEach(keysLineCollection, (line, loopstate, elementIndex) =>
{
/*keysLineCollection[elementIndex]*/
line.Dispatcher.BeginInvoke(new Action(() =>
{
Double topProp = ((Double)line.GetValue(Canvas.TopProperty) - 11.0) * hDelta + 11.0;
switch (topProp - 11.0 < 0)
{
case true:
line.Visibility = Visibility.Hidden;
break;
default:
line.Visibility = Visibility.Visible;
break;
}
line.SetValue(Canvas.TopProperty, topProp);
}));
keysLineCollection[elementIndex] = line;
});
}).Start();
new Thread(delegate ()
{
Parallel.ForEach(keysLabelCollection, (label, loopstate, elementIndex) =>
{
/*keysLabelCollection[elementIndex]*/
label.Dispatcher.BeginInvoke(new Action(() =>
{
Double topProp = (Double)label.GetValue(Canvas.TopProperty) * hDelta;
switch (topProp < 0)
{
case true:
label.Visibility = Visibility.Hidden;
break;
default:
label.Visibility = Visibility.Visible;
break;
}
label.SetValue(Canvas.TopProperty, topProp);
}));
keysLabelCollection[elementIndex] = label;
});
}).Start();
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is Exception)
{
MessageBox.Show(x.ToString(), "error");
}
return false;
});
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString(), "error");
}
我用过
Line[] keysLineCollection = YAxisKeys.Children.OfType<Line>().ToArray();
而不是
IEnumerable<Line> lineCollection = canvas.Children.OfType<Line>();
并将Dispatcher应用于数组中的元素。
它对我很有用。