小鸣新语


  • 首页

  • 标签

  • 分类

  • 归档

Dragablz的MVVM绑定初探

发表于 2017-10-17

Dragablz的MVVM绑定初探

Dragablz(https://github.com/ButchersBoy/Dragablz)是一套使用了Google Modern Design的多窗口选项卡管理框架,可以用在WPF和UWP应用上。

此前,我一般使用AvalonDock做为多文档式应用(MDI)的替代品。Avalondock 功能强大,但是其界面比较传统,与现代设计风格有较大差异。前几天开始使用Dragablz时,发现其应用简单,使用方便,在窗口管理不需要特别复杂的情况下使用Dragablz更加美观。

Dragablz支持内嵌“窗口”,或者称为标签页,和浮动“窗口”,称为工具窗口。下文中只涉及到标签页。

首先看一下主窗口的视图模型(MainWindowViewModel.cs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class MainWindowViewModel:ViewModelBase
{
static MainWindowViewModel _workspace = new MainWindowViewModel();
static MainWindowViewModel _tabHost = new MainWindowViewModel();
//系统的默认VM
public static MainWindowViewModel WorkSpace
{ get { return _workspace; } }
//新窗口的VM
public static MainWindowViewModel TabHost
{ get { return _tabHost; } }
//标签页文档
public ObservableCollection<SoconaViewModel> Documents
{ get; private set; }
//窗口管理器
private readonly IInterTabClient _interTabClient = new SoconaInterTabClient();
public IInterTabClient InterTabClient
{ get { return _interTabClient; } }
//浮动窗口
public ObservableCollection<object> Anchorables { get; private set; }
//活动文档
private SoconaViewModel activeTab;
public SoconaViewModel ActiveTab
{
get { return activePane; }
set
{
activePane = value;
OnPropertyChanged();
}
}
//关闭窗口事件回调
public ItemActionCallback ClosingTabItemHandler
{
get { return ClosingTabItemHandlerImpl; }
}
private void ClosingTabItemHandlerImpl(
ItemActionCallbackArgs<TabablzControl> args )
{
//in here you can dispose stuff or cancel the close
//here's your view model:
var viewModel = args.DragablzItem.DataContext as SoconaViewModel;
Debug.Assert(viewModel != null);
//here's how you can cancel stuff:
//args.Cancel();
if (viewModel.IsDirty)
{
var res = MessageBox.Show(string.Format("Save changes for file '{0}'?", viewModel.Title), "Socona App", MessageBoxButton.YesNoCancel);
if (res == MessageBoxResult.Cancel)
{ return; }
if (res == MessageBoxResult.Yes)
{
if (viewModel.UpdateCommand.CanExecute(null))
{
viewModel.UpdateCommand.Execute(null);
}
}
}
CloseTab(viewModel);
}
}

MainWindow的绑定代码如下(MainWindow.xaml)

1
2
3
4
5
6
7
<!-- a root, named tab control is needed, so when a tab is torn and a new window is created, the new target tab control can be identified -->
<dragablz:TabablzControl x:Name="InitialTabablzControl" SelectedItem="{Binding ActivePane}"
AddLocationHint="After" Style="{StaticResource TabablzControlStyle}" >
<dragablz:TabablzControl.InterTabController>
<dragablz:InterTabController InterTabClient="{Binding InterTabClient}" Partition="2AE89D18-F236-4D20-9605-6C03319038E6" />
</dragablz:TabablzControl.InterTabController>
</dragablz:TabablzControl>

在Window.Resources中加入对应的样式TabablzControlStyle,注意,这在里指定的视图的数据源ItemSource,和关闭窗口回调。最后指定的窗口控制器是不需要改写的,使用库中的类即可。

1
2
3
4
5
6
7
<Style TargetType="{x:Type dragablz:TabablzControl}" x:Key="TabablzControlStyle" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}">
<Setter Property="ItemsSource" Value="{Binding Documents}" />
<Setter Property="ClosingItemCallback" Value="{Binding ClosingTabItemHandler}" />
<Setter Property="HeaderMemberPath" Value="Title" />
<Setter Property="InterTabController" Value="{StaticResource InterTabController}" />
</Style.Triggers>
</Style>

同样在Window.Resources中加入VM中Document的数据模板,这样在向VM.Documents中增加页面视图模型时,就使用匹配的数据模块显示指定的视图。

1
2
3
<DataTemplate DataType="{x:Type vm:SoconaViewModel}">
<v:SoconaView></v:SoconaView>
</DataTemplate>

最后需要实现的是窗口管理器类,这个管理器类用于将一个页面拖动离开当前主窗口,要产生一个新的主窗口,这个类用来管理产生新的主窗口的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
internal class SoconaInterTabClient : IInterTabClient
{
//控制产生新窗口时的逻辑。
public INewTabHost<Window> GetNewHost(IInterTabClient interTabClient, object partition, TabablzControl source)
{
var view = new MainWindow();
var model = MainWindowViewModel.TabHost;
view.DataContext = model;
return new NewTabHost<Window>(view, view.InitialTabablzControl);
}
//控制关闭窗口时的逻辑
public TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window)
{
//当非主窗口中关闭最后一个标签的同时关闭这个窗口
//主窗口可以存在0个标签页
if (window.DataContext == MainWindowViewModel.WorkSpace)
{
return TabEmptiedResponse.DoNothing;
}
else
{
return TabEmptiedResponse.CloseWindowOrLayoutBranch;
}
}
}

这个框架非常好用,和MVVM模型的集成也非常好。感兴趣的可以自己去试用一下。

Hello World

发表于 2017-10-17

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

deep-clustering

发表于 2017-10-17

socona

苟利国家生死以 另请高明不谦虚

3 日志
GitHub ZhiHu E-Mail Twitter Skype
© 2017 socona
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.3