(粗译) Prism and WPF - 定制 Tab region adapter - 02部分

原作者:Raffaeu

上一篇文章我们看到,在WPF中创建定制的并重写默认样式的 TabControl 是相当复杂的,但对于扩展其行为还是很简单的。

作为资深开发者,我通常不喜欢:  1) 能够运行即可, 2) 推倒重来但仅仅写了两次相同的代码。那么这里要做代码重构,或做的更多!

所以,让我们继续以前的文章做要求的工作,制作一个模仿 VS IDE 的应用程序,就是他! 我们看到Prism已有了 RegionAdapter, 因此现在我们仅仅需要一个酷酷的控件. 好的,这里有一个开源项目 Avalon Dock , 他真的不错, 支持 WPF 4并且非常灵活. 因此,为了我们的目标,使用它吧。最终的效果应该是这样:

image

Avalon dock 异常强大,它允许你创建一个完整的支持窗口停靠的WPF应用程序. 但在使用它之前,你需要为它编写定制的 region adapter !

所以,有一个基本概念,在Prism中定制Region Adapter . 你通过下面的方法创建你自己的adapter class ,他继承自RegionAdapterBase<T> :

public sealed class AvalonRegionAdapter :RegionAdapterBase<DocumentPane> 
{ 
public AvalonRegionAdapter(IRegionBehaviorFactoryfactory) 
        : base(factory) 
    { 

    } 

//...

}

Avalon dock 可以做得更多, 你可以创建多种类型的可停靠区域的view, 在当前文章我们仅仅使用它来创建 Tab region adapter 来装载 DocumentPane. 现在 RegionAdapterBase 需要实现三种方法:

protected override IRegion CreateRegion() 
{ 
return new AllActiveRegion(); 
} 

创建一个 region ,指定其使用的 adapter . 在本例中我们想要指定多种类型的View来添加到这个 adapter中, 比如ItemsContainer 或者 TabControl.

protected override void Adapt(IRegion region,DocumentPane regionTarget) 
{ 
    region.Views.CollectionChanged += delegate(Objectsender, NotifyCollectionChangedEventArgs e) 
    { 
        OnViewsCollectionChanged(sender, e, region, regionTarget); 
    }; 
} 

 

现在我们重写了adapt方法. 在本例中这个方法被调用了一次, 因为我只有一个 DocumentPane ,并且接下来我还要监听 Views.CollectionChanged事件. 通过这个我可以在任何时间知道当view从region中加入和移除.

private void OnViewsCollectionChanged(object sender,NotifyCollectionChangedEventArgs e, IRegion region,DocumentPane regionTarget) 
{ 
if (e.Action == NotifyCollectionChangedAction.Add) 
    { 
//Add content panes for each associated view. 
foreach (object item in e.NewItems) 
        { 
UIElement view = item as UIElement; 

if (view != null) 
            { 
DockableContent newContentPane = newDockableContent(); 
                newContentPane.Content = item; 
//if associated view has metadata then apply it. 
                newContentPane.Title = view.GetType().ToString(); 
//When contentPane is closed remove the associated region 
                newContentPane.Closed += (contentPaneSender, args) => 
                { 

                }; 
                regionTarget.Items.Add(newContentPane); 
                newContentPane.Activate(); 
            } 
        } 
    } 
else 
    { 
if (e.Action ==NotifyCollectionChangedAction.Remove) 
        { 

        } 
    } 
} 

 

现在,这里有两个主要步骤. 首先我们想知道项目从集合中添加或移除。如果他添加了我们新创建的DockableContent并在view中设置内容。我们需要设置几个属性如标题和名称。 在我们的例子中,我仅仅添加了view,我们晚一会儿再看怎么实现我们的 TabModel property. 现在我们要做些什么呢?我们要监听标签的关闭事件。为什么呢?因为当Avalon关闭了dock document时我们需要释放相对应的view。

接着,当 regionAdapter 需要关闭view的时候,我们也要释放对应的标签控件.

现在我们稍稍回头,对我们的代码做些改变:

TabViewModel viewModel = ((UserControl)view).DataContext as TabViewModel; 
if (view != null) 
{ 
DockableContent newContentPane = newDockableContent(); 
    newContentPane.Content = item; 
if (viewModel != null) 
    { 
Image img = new Image(); 
        img.Source = new BitmapImage(newUri(@"Resources/Alerts.png", UriKind.Relative)); 
        newContentPane.Title = viewModel.TabModel.Title; 
        newContentPane.IsCloseable = viewModel.TabModel.CanClose; 
        newContentPane.Icon = img.Source; 
    } 

 

这里有一点脏代码,但是我们尝试将View.DataContext对应到TabViewModel类型. 这是正确的类型, NET不会抛出异常 但会返回一个空的实例… 我们将用我们的信息来填充 tab controls .

最终结果是这样:

SNAGHTML388d63e

第一个标签不能被关闭,第二个可以, 我们也在上下文菜单中增加了一个特殊图标. 还有更多, 他仍然是一个WPF 控件,你可以应用你的自定义样式 就是这样!

Ops, 当然,这是新的MainView的代码:

<ad:DockingManager Grid.Column="1" Grid.Row="1" > 
<ad:DocumentPanecal:RegionManager.RegionName="TabRegion"Name="TabRegion"> 
<ad:DockableContent Title="Some title"> 

</ad:DockableContent> 
</ad:DocumentPane> 
</ad:DockingManager> 

转载于:https://www.cnblogs.com/tanCool/archive/2011/02/12/1952767.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值