Prism学习之SilverlightWindowRegionAdapter

很多应用都需要多窗口支持,例如IM通讯工具,多窗口显示也能够提高的操作的灵活性,这个论据可以参考windows OS,但Silverlight中却没有内置提供多窗口显示支持,我们只能自己开发个“窗口”控件了,其实这样也好,省得还要去掉Windows窗口那些默认的显示效果;开发Silverlight或者WPF的人都喜欢用Prism来作为开发框架(Prism2.2发布了,全面支持Silverlight4 );本文讨论的是解决在Prism中使用多窗口的问题。

Prism是靠一堆统一管理的“Region”来动态显示模块界面的:先在需要显示界面的地方放个Region

  < ItemsControl  x:Name ="MainRegion"  Grid.Row ="0"  VerticalAlignment ="Center"  Regions:RegionManager.RegionName ="MainRegion"  Width ="400"  Height ="300" />

 

 然后在模块文件(继承自IModule)中 

this.regionManager.Regions["MainRegion"].Add(view);

 

这样就可以把指定的模块显示在指定的区域当中了。
Prism提供了三种类型的Region,分别是ContentControl、ItemsControl、Selector,偏偏没有用来显示“多窗口”的,我就找啊找啊,终于在这个项目http://compositewpfcontrib.codeplex.com/ 中找到了一个WPF的WindowRegionAdapter,所以我就依葫芦画瓢,给弄出个Silverlight的WindowRegionAdapter。

 

代码
using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;
using  Microsoft.Practices.Composite.Regions;
using  Microsoft.Practices.Composite.Presentation.Regions;
using  System.Collections.Specialized;

namespace  CompositeTest1.Common.Utilities
{
    
public   class  SLWindowRegionAdapter : RegionAdapterBase < Grid >
    {
        
public  SLWindowRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
            : 
base (regionBehaviorFactory)
        { }

        
protected   override   void  Adapt(IRegion region, Grid regionTarget)
        {
        }

        
protected   override  IRegion CreateRegion()
        {
            
return   new  SingleActiveRegion();
        }
        
protected   override   void  AttachBehaviors(IRegion region, Grid regionTarget)
        {
            
base .AttachBehaviors(region, regionTarget);
            WindowRegionBehavior behavior 
=   new  WindowRegionBehavior(regionTarget, region);
            behavior.Attach();
        }
    }
    
public   class  WindowRegionBehavior
    {
        
private   readonly  WeakReference _ownerWeakReference;
        
private   readonly  WeakReference _regionWeakReference;

        
public  WindowRegionBehavior(Grid owner, IRegion region)
        {
            _ownerWeakReference 
=   new  WeakReference(owner);
            _regionWeakReference 
=   new  WeakReference(region);
        }

        
public   void  Attach()
        {
            IRegion region 
=  _regionWeakReference.Target  as  IRegion;
            
if  (region  !=   null )
            {
                region.Views.CollectionChanged 
+=   new  NotifyCollectionChangedEventHandler(Views_CollectionChanged);
                region.ActiveViews.CollectionChanged 
+=   new  NotifyCollectionChangedEventHandler(ActiveViews_CollectionChanged);
            }
        }

        
public   void  Detach()
        {
            IRegion region 
=  _regionWeakReference.Target  as  IRegion;
            
if  (region  !=   null )
            {
                region.Views.CollectionChanged 
-=  Views_CollectionChanged;
                region.ActiveViews.CollectionChanged 
-=  ActiveViews_CollectionChanged;
            }
        }


        
void  window_LostFocus( object  sender, RoutedEventArgs e)
        {
            IRegion region 
=  _regionWeakReference.Target  as  IRegion;
            System.Windows.Controls.Window window 
=  sender  as  System.Windows.Controls.Window;
            
if  (window  !=   null   &&  region  !=   null )
                
if  (region.Views.Contains(window.Content))
                    region.Deactivate(window.Content);
        }

        
void  window_GotFocus( object  sender, RoutedEventArgs e)
        {
            IRegion region 
=  _regionWeakReference.Target  as  IRegion;
            System.Windows.Controls.Window window 
=  sender  as  System.Windows.Controls.Window;
            
if  (window  !=   null   &&   ! region.ActiveViews.Contains(window.Content)  &&  region.Views.Contains(window.Content))
                region.Activate(window.Content);
        }
        
private   void  window_Closed( object  sender, EventArgs e)
        {
            System.Windows.Controls.Window window 
=  sender  as  System.Windows.Controls.Window;
            IRegion region 
=  _regionWeakReference.Target  as  IRegion;

            
if  (window  !=   null   &&  region  !=   null )
                
if  (region.Views.Contains(window.Content))
                    region.Remove(window.Content);
             Grid owner 
=  _ownerWeakReference.Target  as  Grid;
             StackPanel spanel 
=  owner.FindName( " SLWindow " as  StackPanel;
             
if  (spanel  !=   null )
             {
                 Button btn 
=  spanel.FindName(window.Name.ToString().TrimEnd( ' M ' ))  as  Button;
                 spanel.Children.Remove(btn);
             }
        }

        
private   void  ActiveViews_CollectionChanged( object  sender, NotifyCollectionChangedEventArgs e)
        {
            Grid owner 
=  _ownerWeakReference.Target  as  Grid;

            
if  (owner  ==   null )
            {
                Detach();
                
return ;
            }

            
if  (e.Action  ==  NotifyCollectionChangedAction.Add)
            {
                
foreach  ( object  view  in  e.NewItems)
                {
                    System.Windows.Controls.Window window 
=  GetContainerWindow(owner, view);
                    
if  (window  !=   null )
                    {
                        window.Focus();
                    }
                }
            }
        }

        
private   void  Views_CollectionChanged( object  sender, NotifyCollectionChangedEventArgs e)
        {
            Grid owner 
=  _ownerWeakReference.Target  as  Grid;
            
if  (owner  ==   null )
            {
                Detach();
                
return ;
            }
            
if  (e.Action  ==  NotifyCollectionChangedAction.Add)
            {
                
foreach  ( object  view  in  e.NewItems)
                {
                    System.Windows.Controls.Window window 
=   new  System.Windows.Controls.Window();
                    window.GotFocus 
+=   new  RoutedEventHandler(window_GotFocus);
                    window.LostFocus 
+=   new  RoutedEventHandler(window_LostFocus);
                    window.Closed 
+=   new  EventHandler(window_Closed);
                    window.Content 
=  view;

                 
                    StackPanel spanel 
=  owner.FindName( " SLWindow " as  StackPanel;
                    
if  (spanel  !=   null )
                    {
                        
int  index  =  spanel.Children.Count  +   1 ;
                        Button btn 
=   new  Button() { Name  =   " Window "   +  index, Content  =   " 窗口 "   +  index };
                        window.Name 
=   " Window "   +  index + " M " ;
                        window.TitleContent 
=   " 窗口 "   +  index;
                        btn.Tag 
=  window;
                        btn.Click 
+=   new  RoutedEventHandler(btn_Click);
                        spanel.Children.Add(btn);
                    }
                   
                    window.Container 
=  owner;
                    window.Show(DialogMode.Default);
                }
            }
            
else   if  (e.Action  ==  NotifyCollectionChangedAction.Remove)
            {
                
foreach  ( object  view  in  e.OldItems)
                {
                    System.Windows.Controls.Window window 
=  GetContainerWindow(owner, view);

                    
if  (window  !=   null )
                        window.Close();
                }
            }
        }

        
void  btn_Click( object  sender, RoutedEventArgs e)
        {
            Button btn 
=  sender  as  Button;
            System.Windows.Controls.Window window 
=  btn.Tag  as  System.Windows.Controls.Window;
            
if  (window  !=   null )
            {
                window.Visibility 
=  window.Visibility  ==  Visibility.Visible  ?  Visibility.Collapsed : Visibility.Visible;
            }
        }


        
private  System.Windows.Controls.Window GetContainerWindow(Grid owner,  object  view)
        {
            
foreach  (UIElement ui  in  owner.Children)
            {
                System.Windows.Controls.Window window 
=  ui  as  System.Windows.Controls.Window;
                
if  (window  !=   null   &&  window.Content  ==  view)
                    
return  window;
            }
            
return   null ;
        }
    }
}

 

 

自定义的RegionAdapter要实现RegionAdapterBase<T>,这个T就是要承载Region的容器owner,我们的Window控件是需要一个Grid的容器的,所以就是RegionAdapterBase<Grid>,注意里面并没有直接实现Adapt方法,而是在重载AttachBehaviors方法中实现了对region.Views和region.ActiveViews的管理,并实现了窗口操作对View的影响,里面我还加了个类似于Windows任务栏的功能,当然实现的不完善,需要改进。

我们需要把自定义的RegionAdapter介绍给Prism中,让Prism认识他,通过在Bootstrapper中重载ConfigureRegionAdapterMappings方法实现

代码
   protected   override  RegionAdapterMappings ConfigureRegionAdapterMappings()
        {
            RegionAdapterMappings regionAdapterMappings 
=  Container.TryResolve < RegionAdapterMappings > ();
            IRegionBehaviorFactory regionBehaviorFactory 
=  Container.TryResolve < IRegionBehaviorFactory > ();
            
if  (regionAdapterMappings  !=   null   &&  regionBehaviorFactory  !=   null )
            {
                regionAdapterMappings.RegisterMapping(
typeof (Grid),  new  SLWindowRegionAdapter(regionBehaviorFactory));
            }
            
return   base .ConfigureRegionAdapterMappings();
        }

 

然后在我需要承载弹出窗口的Grid更改成

< Grid  x:Name ="contentGrid"  Grid.Row ="1"  Regions:RegionManager.RegionName ="SLWindow" >

 

然后在要呈现弹出窗口的地方

 IRegion region  =   this .regionManager.Regions[ " SLWindow " ];
            
if  (region  !=   null )
                region.Add(view);

 

搞定,看效果:
1、自动载入模块A,在模块A中弹出窗口显示模块A中的其他View


Prism学习之SilverlightWindowRegionAdapter_第1张图片

2、手动载入模块B,并在新的窗口中显示模块B的View

Prism学习之SilverlightWindowRegionAdapter_第2张图片

 

你可能感兴趣的:(Prism学习之SilverlightWindowRegionAdapter)