【发布时间】:2017-12-12 12:35:02
【问题描述】:
首先我不得不猜测我对异步没有太多经验。
我正在使用 VS2015 开发 WPF 应用程序,其中我有一个掩码设计器。 在那里,我可以通过拖放、移动和调整它们的大小将控件添加到画布。 大小和位置的更改会暂时存储在字典中,稍后通过单击“保存”按钮将其保存到数据库中。
为了优化更新速度,我认为最好用异步 System.Threading.Tasks.Parallel.ForEach 替换同步 foreach。 但是现在我有一个问题,我不能在那个循环内使用一些 WPF 控件——比如控件所在的画布——因为它们属于主线程。
如何在循环中访问这些控件?
这是我的代码中的一个专家,这让我在这个时候遇到了问题:
Parallel.ForEach(ChangedElements, (changedElement) =>
{
FrameworkElement element = elementHelper.GetElementFromPanel(changedElement.Value, designerwindow.maskDesignerPanel);
elementHelper.UpdateElementPositionAndSize(element, designerwindow, inputFieldList);
});
“ChangedElements”是包含已更改 WPF 元素名称的字典。 最初它是类型,但我将其更改为,因此键和值包含控件的名称/标识符。 “designerWindow”是对 WPF 窗口的引用,“maskDesignerPanel”是画布的名称。 在运行时,当我尝试从画布的子集合中获取元素时,方法 GetElementFromPanel 内部出现错误。 在那种情况下,我无法访问子集合,因为它属于主线程。
这里是GetElementFromPanel方法的代码:
public FrameworkElement GetElementFromPanel(string elementName, Canvas panel)
{
FrameworkElement element = null;
foreach (FrameworkElement child in panel.Children)
{
if (child.Name == elementName)
{
element = child;
break;
}
}
return element;
}
【问题讨论】:
-
你试过用dispatcher拉取值吗?
-
你不。反正你不需要。有几十个重复的问题展示了如何使用 async/await、IPProgress 或根本不同步 - 如果您使用数据将您绑定到 ViewModel,您将不必担心跨线程访问。修改 ViewModel 属性并引发 INotifyPropertyChanged 事件足以让 WPF 知道 它 需要去拉动更改
-
PS,不要尝试使用调度程序或 .Invoke。这是 a) 不需要,因为引入了 async/await,b) 它是糟糕的 WPF。使用数据绑定,不要尝试直接修改控件
-
For optimizing the speed of the updates你有性能问题吗?如果你这样做了,多线程不是答案。您看到的允许在屏幕上拖动/移动对象的应用程序不使用多线程。它们限制重绘以避免抖动。例如,他们在操作完成之前不更新 UI,或者他们禁用 UI 更新。或者它们将移动和更改存储在列表中,并且仅在拖动操作结束时应用它们。 WPF 本身允许您指定动画、过渡、故事板 -
@Panagiotis Kanavos:我不直接修改控件。我只想将它们的位置和大小保存到我的一个数据库表中。
标签: c# wpf multithreading