原文: WPF MVVM模式中,通過指令實作窗體拖動、跳轉以及顯隐控制
在WPF中使用MVVM模式,可以讓我們的程式實作界面與功能的分離,友善開發,易于維護。但是,很多初學者會在使用MVVM的過程中遇到一個顯而易見且無法回避的問題,那就是不同的窗體之間如何跳轉?很多人在介紹MVVM的使用時,都沒有明顯提到該如何解決這一問題,不知是因為覺得太簡單了還是其他原因。
部落客根據自己的開發經驗,寫了一個簡單的示例程式,介紹MVVM模式中,如何通過指令來控制窗體的跳轉、拖動與顯隐控制。
先看效果:

新窗體可以為自定義樣式窗體,滑鼠拖動标題框,可以拖動整個窗體,點選關閉按鈕,窗體隐藏。
下面是實作操作:
1.定義指令類ActionCommand.
使用MVVM模式的第一步,就是要實作自己的指令類。
public class ActionCommand<T> : ICommand where T : class
{
private Predicate<T> _canExecuteMethod;
private Action<T> _executeMethod;
public ActionCommand(Action<T> executeMethod)
{
_canExecuteMethod = null;
_executeMethod = executeMethod;
}
public ActionCommand(Action<T> executeMethod, Predicate<T> canExecuteMethod)
{
_canExecuteMethod = canExecuteMethod;
_executeMethod = executeMethod;
}
public bool CanExecute(object parameter)
{
return _canExecuteMethod == null ? true : _canExecuteMethod(parameter as T);
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
if (_executeMethod != null)
{
_executeMethod(parameter as T);
}
UpdateCanExecute();
}
public void UpdateCanExecute()
{
var handls = CanExecuteChanged;
if (handls != null)
{
handls(this, new EventArgs());
}
}
}
2.在App.xaml中定義窗體導航實作代碼以及窗體操作指令
/// <summary>
/// App.xaml 的互動邏輯
/// </summary>
public partial class App : Application
{
private static bool _bDebug = true;
public static void MessageBox(string text, string caption)
{
if (_bDebug)
{
System.Windows.MessageBox.Show(text, caption);
}
}
private static Dictionary<string, Window> _cacheWindow = new Dictionary<string, Window>();
public static Window NavigationToWindow(string wndUri, bool createNew = false, bool cache = true, string cacheKey = null)
{
Window window = null;
string key = string.IsNullOrWhiteSpace(cacheKey) ? wndUri : cacheKey;
if (createNew)
{
window = App.Current.GetType().Assembly.CreateInstance(wndUri) as Window;
if (cache && window != null)
{
if (!_cacheWindow.ContainsKey(key))
{
_cacheWindow.Add(key, window);
}
}
}
else
{
if (_cacheWindow.ContainsKey(key))
{
window = _cacheWindow[key];
}
else
{
window = App.Current.GetType().Assembly.CreateInstance(wndUri) as Window;
if (cache && window != null)
{
_cacheWindow.Add(key, window);
}
}
}
return window;
}
/// <summary>
/// 顯示窗體指令
/// </summary>
public static ICommand ShowWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("參數不能為空!", "[App][ShowWindowCommand]");
return;
}
string[] arrs = p.Split(',');
string wndUri = null, cacheKey = null;
bool createNewWnd = false, cacheWnd = true;
try
{
if (arrs.Length > 3)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
cacheWnd = Convert.ToBoolean(arrs[2]);
cacheKey = arrs[3];
}
else if (arrs.Length > 2)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
cacheWnd = Convert.ToBoolean(arrs[2]);
}
else if (arrs.Length > 1)
{
wndUri = arrs[0];
createNewWnd = Convert.ToBoolean(arrs[1]);
}
else
{
wndUri = arrs[0];
}
Window window = NavigationToWindow(wndUri, createNewWnd, cacheWnd, cacheKey);
if (window == null)
{
App.MessageBox("未找到導航窗體" + "[" + wndUri + "]", "[App][ShowWindowCommand]");
return;
}
window.Owner = App.Current.MainWindow;
if (!window.IsVisible)
{
window.Show();
}
else
{
window.Hide();
}
}
catch (Exception ex)
{
App.MessageBox(ex.Message, "[App][ShowWindowCommand]");
}
}
);
}
}
/// <summary>
/// 隐藏窗體指令
/// </summary>
public static ICommand HideWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("參數不能為空!", "[App][HideWindowCommand]");
return;
}
Window window = App.NavigationToWindow(p);
if (window != null)
{
window.Hide();
}
}
);
}
}
/// <summary>
/// 拖動窗體指令
/// </summary>
public static ICommand DragMoveWindowCommand
{
get
{
return new ActionCommand<string>(p =>
{
if (string.IsNullOrWhiteSpace(p))
{
App.MessageBox("參數不能為空!", "[App][DrawMoveWindowCommand]");
return;
}
Window window = App.NavigationToWindow(p);
if (window != null)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
window.DragMove();
}
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
}
}
);
}
}
}
3.在主窗體中使用ShowCommand指令來實作窗體導航。
<Window x:Class="WpfMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfMVVM"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Width="100" Height="40" Content="打開新窗體" Command="{x:Static local:App.ShowWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
</Grid>
</Window>
4.在自定義窗體CustomWindow.xaml中使用指令來實作窗體拖動和顯隐控制。
為了使得Grid中的MouseMove事件能夠響應指令綁定操作,導入blend中的類庫:System.Windows.Interactivity.dll。并在頁面中導入xml命名空間:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"。這樣就可以實作WPF中任意事件的指令響應。
<Window x:Class="WpfMVVM.View.CustomWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfMVVM"
Title="CustomWindow" Height="300" Width="300"
WindowStyle="None" AllowsTransparency="True"
ShowInTaskbar="False"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="{StaticResource BoardHead}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="标題" Style="{StaticResource BoardTitle}"/>
<Button Grid.Column="1" Style="{StaticResource CloseBtn}"
Command="{x:Static local:App.HideWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseMove">
<i:InvokeCommandAction Command="{x:Static local:App.DragMoveWindowCommand}"
CommandParameter="WpfMVVM.View.CustomWindow"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
<Grid Grid.Row="1" Background="{StaticResource BoardBody}">
<Image Source="/Resource/sun.png" Stretch="Uniform"/>
</Grid>
</Grid>
</Window>
通過以上步驟操作,我們便可以實作窗體之間的導航以及自定義窗體的拖動控制以及顯隐控制。
完整代碼下載下傳:
http://download.csdn.net/detail/tianwenxue/9078205。
本文原創,轉載請注明出處。