WPF本身并没有提供MDI实现,但是有个简单的方法可以实现MDI方法。
第一步:添加引用API方法
- usingSystem;
- usingSystem.Runtime.InteropServices;
- namespaceWPFMdi{
- publicclassWin32Native{
- [DllImport("user32.dll",EntryPoint="SetParent")]
- publicexternstaticIntPtrSetParent(IntPtrchildPtr,IntPtrparentPtr);
- }
- }
第二步:子父窗口设置
- usingSystem.Windows;
- usingSystem.Windows.Interop;
- namespaceWPFMdi{
- ///<summary>
- ///MainWindow.xaml的交互逻辑
- ///</summary>
- publicpartialclassMainWindow:Window{
- publicMainWindow(){
- InitializeComponent();
- }
- privatevoidbutton1_Click(objectsender,RoutedEventArgse){
- ChildWindowwin=newChildWindow();
- win.Show();
- //创建MDI窗体
- WindowInteropHelperparentHelper=newWindowInteropHelper(this);
- WindowInteropHelperchildHelper=newWindowInteropHelper(win);
- Win32Native.SetParent(childHelper.Handle,parentHelper.Handle);
- }
- }
- }
虽然实现了MDI窗口,但是还有一些问题:先设置好主窗口背景图片(为了能演示出效果),然后创建一个子窗口,当移动子窗口时,子窗口的边缘产生了花屏效果。
分析了原因,应该是当窗口移动时,渲染产生了问题。所以我迫切希望在子窗口的LocationChanged事件中重绘,WPF中没有Invalidate方法,试了很多方法也没有成功。请教高手如何解决这个问题,或者如何重绘子窗口,使其边缘不产生花屏效果。
我的临时解决方案:我发现当窗口大小发生变化后,窗口会自动重绘,边缘的花屏也就没了,正常了。于是我在LocationChanged事件中更改窗口大小
- usingSystem;
- usingSystem.Windows;
- namespaceWPFMdi{
- ///<summary>
- ///ChildWindow.xaml的交互逻辑
- ///</summary>
- publicpartialclassChildWindow:Window{
- publicChildWindow(){
- InitializeComponent();
- }
- #regionWindow重绘处理
- intcount=0;
- privatevoidWindow_LocationChanged(objectsender,EventArgse){
- if(count<10){
- this.Width+=0.101;
- }elseif(count<20){
- this.Width-=0.102;
- }
- count=++count%20;
- }
- #endregion
- }
- }
项目下载
======================================================================================
微软论坛对于该问题的回答:
很遗憾的是,WPF本身没有实现MDI,所以你会想到用Host的方式,将一个窗体的句柄设置为另一窗体的子窗体 (调用 SetParent API)
这一点就会引起问题,WPF不同于一般的Win32程序,本身内容是没有句柄的,因为它通过DX去实现绘制,所以消息循环就不同于Win32的窗体了,不能有一个消息队列来对应每一个组件,来各自处理不同的消息,来处理每一次的重绘消息。何况,WPF使用DX后,为了提高性能,缓存了大量的UI信息,使并不是每次窗体区域被遮住或者改变都要进行重绘的,所以上述两点就很显然会导致大小改变的时候边缘有无效区域或者花屏产生。
你的临时方案是可行的,但是我还是要推荐你使用下面的WPF MDI解决方案:http://wpfmdi.codeplex.com/
他已经很好的实现了父子窗体间的消息传递了。