zoukankan      html  css  js  c++  java
  • 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


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

     
  • 相关阅读:
    BugKu web 矛盾
    BugKu 域名解析
    Dummy game
    BugKu 变量1
    BugKu web5
    递归算法
    Django进阶(转载)
    centos 7防火情配置
    cenos7切换阿里源
    centos7 编译安装nginx
  • 原文地址:https://www.cnblogs.com/xiaozhuang/p/1751268.html
Copyright © 2011-2022 走看看