将sample framework 做成用户控件
可能本文比较适合对 sample framework 有稍微了解的人。
前段时间研究了一下directx sdk里的sample framework。sample framework是一个非常强大的3d 引擎。这里有些心得体会想和大家一起分享,希望可以得到一些更强大和实际的应用。
今天我想写一下如何将sample framework做成控件。我里想的不仅仅是将 sample framework 做成用户控件, 而且可以实现动态的load dll.
首先创建一个类 IFrameWork:
{
public virtual void OnFrameMove(Device device, double totalTime, float elapsedTime)
{
}
public virtual void OnFrameRender(Device device, double totalTime, float elapsedTime)
{
}
public virtual bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
{
return true;
}
public virtual void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
{
}
private Framework sampleFramework = null;
public virtual Framework Framework
{
get
{
return this.sampleFramework;
}
set
{
this.sampleFramework = value;
}
}
}
这里IFrameWork 继承自 UserControl, IDeviceCreation, IFrameworkCallback.
这里为什么要加一个sampleFramework 属性等下再解释.
对于把sample framework做成控件最关键的地方该在于 mainloop() 函数. 我看www.mdxinfo.com上看过一篇将原来的 main()的函数改成InitializeGraphics();
而且在方法的最后将 this.sampleFramework.MainLoop(); 删掉。
然后在主程序的main() 函数中添加
Form1 form = new Form1();
form.Show();
form.directXWindow.Framework.MainLoop();
来运行出控件模型。
其实这里有很多值得改进的地方。我们仔细分析一下MainLoop()方法。
{
..
//关键就是从这里开始
using (System.Windows.Forms.Control app = Window)
{
// Hook the application's idle event
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
// Start the application
if (app is System.Windows.Forms.Form)
{
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
}
else
{
// Show the window
app.Show();
System.Windows.Forms.Application.Run();
}
}
State.IsInsideMainloop = false;
}
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
是在应用程序空闲的时候调用了绘图的方法。
而
{
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
}
else
{
// Show the window
app.Show();
System.Windows.Forms.Application.Run();
}
是把函数的windows窗体的显示放在了这个方法里,而且占据了主线程。
所以出现上面才会采取将mainloop方法放在主窗体里。
这里面我们其实可以有更好的方法去实现:将上面的一段代码给删除掉。把主线程还给form的main() 函数。
我们添加一个方法:
{
System.Windows.Forms.Application.Idle -= new EventHandler(OnApplicationIdle);
}
这个函数的用法在接下来的使用中就会明白。
到了这一步以后我们基本上可以实现把sample framework 做成一个用户控件了。
但是如何实现动态的load dll。
将以下代码:
{
public override void OnFrameMove(Device device, double totalTime, float elapsedTime)
{
}
public overridevoid OnFrameRender(Device device, double totalTime, float elapsedTime)
{
..
}
public overridebool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
{
}
public overridevoid ModifyDeviceSettings(DeviceSettings settings, Caps caps)
{
.
}
private Framework sampleFramework = null;
public override Framework Framework
{
get
{
return this.sampleFramework;
}
set
{
this.sampleFramework = value;
}
}
.
}
编译成dll。
在主窗体里:
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Multiselect = true;
if (DialogResult.OK == dlg.ShowDialog())
{
string sFileName = dlg.FileName;
Type[] types = null;
try
{
types = Assembly.LoadFile(sFileName).GetTypes(); //动态加载dll
foreach (Type type in types)
{
if (type.IsSubclassOf(typeof(IFrameWork)))
{
//D3dWindow是IFrameWork类型,就是我们的控件 。用于显示3d模型。
D3DWindow.Framework.RemoveIdleDelegate(); // 释放掉 System.Windows.Forms.Application.Idle委托。在新的控件实例中才可以重新添加委托,绘制新的图形
this.splitContainer1.Panel1.Controls.Remove(D3DWindow); //删除掉原来的控件
D3DWindow = (IFrameWork)type.InvokeMember(null, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, null, null);
this.D3DWindow.Dock = System.Windows.Forms.DockStyle.Fill;
this.D3DWindow.Location = new System.Drawing.Point(0, 0);
this.D3DWindow.Name = "D3DWindow";
this.D3DWindow.Size = new System.Drawing.Size(598, 506);
this.D3DWindow.TabIndex = 1;
this.splitContainer1.Panel1.Controls.Add(D3DWindow); //加载新的控件。
}
}
}
catch (Exception ex)
{
ex.ToString();
}
}
}
到这里所有的工作就完成了。