C# 将对象所有权传递给WPF应用程序中的其他线程
编辑1: 显然,我已经开始以错误的方式在WPF环境中实现3D渲染。Ofc下面我的问题有一个解决方案,但我建议阅读Sheridan答案的更新,并使用他的建议来实现这一点。它不仅安全,而且性能更好。虽然理解它有点复杂,但一旦理解它,就可以开始在WPF中渲染多个3D应用程序。 谢里登,谢谢你的帮助C# 将对象所有权传递给WPF应用程序中的其他线程,c#,wpf,multithreading,c#-4.0,C#,Wpf,Multithreading,C# 4.0,编辑1: 显然,我已经开始以错误的方式在WPF环境中实现3D渲染。Ofc下面我的问题有一个解决方案,但我建议阅读Sheridan答案的更新,并使用他的建议来实现这一点。它不仅安全,而且性能更好。虽然理解它有点复杂,但一旦理解它,就可以开始在WPF中渲染多个3D应用程序。 谢里登,谢谢你的帮助 问题, 我是WPF的新手,我想用WPF设计一个连续渲染(就像在游戏应用程序中一样)。我使用多线程来提供更好的UI控件(启动/停止按钮fe)。或者,可以通过使用无限循环渲染3D世界来处理事件 但是,我的问题
问题, 我是WPF的新手,我想用WPF设计一个连续渲染(就像在游戏应用程序中一样)。我使用多线程来提供更好的UI控件(启动/停止按钮fe)。或者,可以通过使用无限循环渲染3D世界来处理事件 但是,我的问题是,在运行程序时,我得到了一个
无效操作未处理的错误。问题是有一个对象是主线程的属性,因此新线程可能无法访问它
从XAML文件
<Grid>
<!-- ui controls omitted ... -->
<Viewport3D Name="myViewport" ClipToBounds="True">
<!-- all inits, camera, pos, ... -->
</Viewport3D>
</Grid>
在currViewport.Children.Count方法中捕获错误。如前所述,问题在于当前线程没有该对象的所有权。这是我在多线程处理经验中第一次面对这个问题。我四处寻找,但找不到解决办法
有人知道如何传递Viewport3D对象的所有权,或者一个好的解决方法吗?首先,我想说的是,WPF不是一个开发除最简单的游戏之外的所有游戏的好框架。。。我建议改用微软这样的游戏框架
但是,如果您坚持使用WPF,那么我想提请您注意这个事件。它基本上使用主机的帧速率来渲染图形过程,避免了使用计时器的需要
您还应该查看MSDN上的页面,以获取更多有用的信息和代码示例
另外,请阅读《WPF控制开发释放:构建高级用户体验》一书的摘录:
一些读者可能认识到这种方法和高端图形之间的相似性
像DirectX这样的子系统。不要将CompositionTarget.Rendering误认为是良好的注入
指向创建基于WPF的游戏图形引擎。高端图形和超高分辨率
帧速率不是WPF动画这一特定方面的目标
与Dispatchermer方法类似,基于CompositionTarget.Rendering的动画
也没有时间限制。但是,这些事件将与渲染线程同步
在比分派器更平滑的动画中。此外,也没有必要启动和启动
停止计时器,尽管您可能必须分离并附加事件处理程序以提高性能
表演
更新>>>
在发现这只是一个课程项目之后,我将忽略我之前的评论和到目前为止您的代码示例。当已有渲染系统时,不要尝试创建新的渲染系统。相反,您应该遵循以下方法:
创建实现INotifyPropertyChanged
接口并具有X
、Y
和DirectionVector
(可以是Size
struct)公共属性的数据对象
添加一个Move
方法(或Swim
方法,用于Fish
类),在该方法中,根据DirectionVector
属性的值更新数据对象的X
和Y
属性
将列表框
控件添加到用户界面
创建集合属性以保存数据对象、添加项并将集合绑定到列表框.ItemsSource
属性
创建一个DataTemplate
来定义Fish
对象的外观。。。您可以使用Path
类来绘制它们,甚至可以使用RotateTransform
来旋转它们(可以从DirectionVector
属性计算角度)。在DataTemplate
中,可以将X
和Y
属性绑定到“Margin”属性
最后,添加一个无限循环(可能带有一个中断选项),在该循环中,迭代数据对象集合并对每个对象调用Move()
。这将更新数据对象在列表框中的位置作为一般规则,在WPF中唯一可以更改线程效忠的对象是那些从可自由化的
派生的对象。(例如,Model3D
是可自由化的,因此,Light
和GeometryModel3D
等都是可自由化的)
直接参与可视化树的元素不是从Freezable
派生的。它们源自视觉(通常,尽管不总是,通过FrameworkElement
)。因此,视觉元素永远与创建它们的线程相关联。Freezable通常是告诉可视化树元素做什么的描述性项目。例如,画笔(无论是实体、渐变填充、图像画笔还是其他)都是可自由化的,但要使用画笔进行某些操作,您需要将其用作某些视觉元素的属性(即不可自由化的属性),例如,矩形的填充
因此Model3D
属于这一类-它是对3D模型的描述,但实际上不知道如何渲染自己。您可以将此描述提供给某些确实知道如何渲染模型的视觉元素(例如,Viewport3D
)
因此,可以在工作线程上构建Model3D
,然后将其传递给UI线程
但是,只有在通过调用Freeze/// <summary>this method is done to render the 3D app in other thread.</summary>
private void Runtime(Viewport3D vp) {
System.Diagnostics.Debug.WriteLine("runtime ");
Render3D r3d = new Render3D(vp);
// actual startup
while (keepRunning) {
r3d.Init3D();
}
}
/// <summary>this method toggles the game runtime</summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StartOrStop(object sender, RoutedEventArgs e) {
keepRunning = !keepRunning;
if (keepRunning) {
buttonStartStop.Content = "Stop";
// thread
t1 = new Thread( () => Runtime(myViewport) );
t1.Start();
}
else {
buttonStartStop.Content = "Start";
t1.Abort();
}
}
// constructor
internal Render3D(Viewport3D v) {
currViewport = v;
}
/// <summary>get called in loops to render gfx</summary>
internal void Init3D() {
// clear rendered view
ClearRenderWindow();
// add landscape
AddLandScape();
}
/// <summary>clear window to re-render gfx</summary>
private void ClearRenderWindow() {
ModelVisual3D mv;
// ***** error got caught here below ******
for (int i = currViewport.Children.Count - 1; i >= 0; i--) {
mv = (ModelVisual3D)currViewport.Children[i];
if (mv.Content is DirectionalLight == false) currViewport.Children.Remove(mv);
}
}