【WPF】对Frame控件的Content属性做绑定时出现的一个小问题

时间:2021-08-17 14:17:22

修改:经过研究,发现只要在Frame上设置JournalEntry.KeepAlive="True"就可以使用第一种绑定到Source的最简单的办法来实现文中的效果。不用自己管理Page

 

这几天给给别人做了几个Demo,但觉得每个Demo都做一个工程太麻烦,不好管理,于是决定把每个Demo都各自用Page,然后通过一个列表,可以选择各个页面来查看。就如下图的效果:

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题

 

当从左边选中一项后,右边的Frame会展示相应的内容。

我采用了一个xml文件来描述相关的信息,示例如下:

 

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题<? xml version="1.0" encoding="utf-8"  ?>
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
< Pages >
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题  
< Page  Name ="Page1"  Uri ="/FrameContent;Component/Page1.xaml" />
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题  
< Page  Name ="Page2"  Uri ="/FrameContent;Component/Page2.xaml" />
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
</ Pages >

这是一个非常简单的描述,每个Page项描述这个Page的Name和对应的xaml文件,然后我们可以简单用下面的方式来绑定这些信息来达到目的:

 

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题< ListBox  x:Name ="ListBox1"
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题          ItemsSource
=" {Binding Source={StaticResource ListSource}} "  
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题          DisplayMemberPath
="@Name" />
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
<!--  最简单的方式就是用Frame的Source来做绑定,不过这样会导致每次都生成新的实例  -->
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
< Frame  DataContext =" {Binding ElementName=ListBox1, Path=SelectedItem} "  
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题       Source
=" {Binding XPath=@Uri} " />

 

不过,这样有一个小小的问题在于,每次我切换Page的时候,都将重新生成一个Page的实例,以前在Page上做的一些操作会消失。这不是我想要的,我希望有一个类似于PagePool的东西来缓存我这些创建好的页面,这样在切换的时候会减少创建实例的开销,同时可以保证无论怎么切换始终是同一个Page的实例。于是我做了如下的更改:

 

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题< ListBox  x:Name ="ListBox1"
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题         ItemsSource
=" {Binding Source={StaticResource ListSource}} "  
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题         DisplayMemberPath
="@Name" />
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
< Frame  x:Name ="PageHost1"
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题       NavigationUIVisibility
="Hidden"
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题       Content
=" {Binding ElementName=ListBox1, Path=SelectedItem, Converter={StaticResource Converter}} " />

 

我直接把Frame的Content属性绑定到选中的项上,并且用一个Converter来返回Page的实例,在Converter里面,我用一个Dictionary来保存创建过的页面,保证它们只会被创建一次:

 

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题public   class  FrameContentConverter : IValueConverter
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题【WPF】对Frame控件的Content属性做绑定时出现的一个小问题    
{
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题        
// 使用Page池来减少创建Page的开销
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
        private Dictionary<string, Page> _pagePool = new Dictionary<string, Page>();
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题【WPF】对Frame控件的Content属性做绑定时出现的一个小问题        
IValueConverter Members
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题    }

 

理论上来说,这应该工作良好,然而,实际上却发生一点小小的意外:

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题

Frame展示的内容只跟第一次选中的项有关,其后无论如何切换,Frame的内容均不受影响

难道是Frame的Content属性默认是以OneTime的模式来绑定的?于是我显示地指定Mode=OneWay,结果依然如此。

莫非Frame的Content属性只能指定一次?好吧,既然正着来不行,那我就试试反着的。

索性,我把ListBox的SeletedItem使用OneWayToSource的模式绑定到Frame的Content属性上。当然,这种情况下,FrameContentConverter里面的ConvertBack方法需要实现。

 

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题< ListBox  x:Name ="ListBox2"  
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题         ItemsSource
=" {Binding Source={StaticResource ListSource}} "
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题         DisplayMemberPath
="@Name"
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题         SelectedItem
=" {Binding ElementName=PageHost2, Path=Content, Converter={StaticResource Converter}, Mode=OneWayToSource} " />
【WPF】对Frame控件的Content属性做绑定时出现的一个小问题
< Frame  x:Name ="PageHost2"  NavigationUIVisibility ="Hidden" />

 

采用这种方式后,一切正常了:

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题【WPF】对Frame控件的Content属性做绑定时出现的一个小问题

 

这说明,Frame的Content属性不是只能设置一次的,只是在对Frame的Content属性做绑定时,由于某种未知的原因,无法对数据源的变化产生响应,鉴于我目前的系统是Vista SP1,上次的Frame出现了渲染上的问题,这次我也没有找没装SP1的机子做测试,所以我并不能确定这是WPF本身的BUG还是sp1引起的问题,还是我某个地方没有弄好造成的。

做了一个对比的示例,有兴趣的读者可以下载回去看看。http://files.cnblogs.com/RMay/FrameContent.rar

【WPF】对Frame控件的Content属性做绑定时出现的一个小问题