本文章提供如何
- 透過MVVM概念實現WPF多視窗畫面
- 將個別視窗顯示在指定螢幕中,與可能會犯的錯
在WPF的概念中,一個WPF僅會有一個application可以執行,而一個application可以顯示一個window(視窗),若需多視窗,只要多新增需要數量的window,並需設定其中一window為主視窗,本文以兩個視窗為範例:
兩個視窗的結構
主視窗(MainWindow)擁有子視窗(SlaveWindow);MainWindowModel擁有SlaveWinowModel,以保持結構的乾淨與親屬關係
當MainWindow與SlaveWindow的資料需要互相連動(例如兩個視窗操作相同資料時),則可採用以下做法:
MainWindowModel
// Fields
private SlaveWindowModel _slaveWindowModel = null;
// Constructors
public MainWindowModel(SlaveWindowModel slaveWindowModel)
{
_slaveWindowModel = slaveWindowModel;
// Handlers
_slaveWindowModel.ButtonClicked += this.ButtonClicked;
}
// Methods
public void ButtonClicked(string input)
{
// Do Something
// Slave
_slaveWindowModel.UpdateView(input);
}
SlaveWinowModel
// Constructors
public SlaveWindowModel()
{
}
// Events
public Action<string> ButtonClicked;
private void OnButtonClicked(string input)
{
#region Contracts
if (string.IsNullOrEmpty(input)) throw new ArgumentException();
#endregion
// Raise
var handler = this.ButtonClicked;
if (handler != null)
{
handler(input);
}
}
// Methods
public void UpdateView(string input)
{
// Update
}
子視窗在特定螢幕開啟並放大(錯誤示範)
在主視窗(MainWindow)中創立一個子視窗(SlaveWindow),並且將SlaveWindow的ViewModel提供給自己的ViewModel,使之可以操控SlaveWindowModel
MainWindow
// Fields
private System.Windows.Window _slaveWindow;
// Constructors
public MainWindow(int slaveScreenPosition)
{
// Initailize
this.InitializeComponent();
// Start Slave Window
_slaveWindow = new SlaveWindow(slaveScreenPosition);
_slaveWindow.Show();
// DataContext
this.DataContext = new MainWindowModel(_slaveWindow.DataContext);
}
SlaveWindow
using System.Windows;
using System.Windows.Forms;
public SlaveWindow(int screenPosition)
{
// Initailize
this.InitializeComponent();
// Screen.AllScreens.Length會先取得所有螢幕,確保指定螢幕存在
if (Screen.AllScreens.Length >= (screenPosition + 1))
{
// 取得指定螢幕
Screen screen = Screen.AllScreens[screenPosition];
// 將Window畫布移至該螢幕的工作區
System.Drawing.Rectangle r1 = screen.WorkingArea;
this.Top = r1.Top;
this.Left = r1.Left;
// Maximized Window
this.WindowState = WindowState.Maximized;
this.Left = screen.WorkingArea.Left;
this.Top = screen.WorkingArea.Top;
this.Width = screen.WorkingArea.Width;
this.Height = screen.WorkingArea.Height;
}
// DataContext
this.DataContext = new SlaveWindowModel();
}
將SlaveWindow指定在規定的螢幕中打開,並且將視窗放至最大,
但要注意的是,如果這樣寫的話,Windows會自動把視窗放大並開在主螢幕
子視窗在特定螢幕開啟並放大(正確示範)
必須改成一開始是普通視窗且移置想要的螢幕上,在發生Window.Loaded事件時,才把視窗放大,才能確保Windows不會亂動該視窗,作法如下:
MainWindow
// Fields
private System.Windows.Window _slaveWindow;
// Constructors
public MainWindow(int slaveScreenPosition)
{
// Initailize
this.InitializeComponent();
// Start Slave Window
_slaveWindow = new SlaveWindow(slaveScreenPosition);
// 增加Window_Loaded事件
_slaveWindow.Loaded += Window_Loaded;
_slaveWindow.Show();
// DataContext
this.DataContext = new MainWindowModel(_slaveWindow.DataContext);
}
// Handlers
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var senderWindow = sender as System.Windows.Window;
senderWindow.WindowState = WindowState.Maximized;
senderWindow.WindowStyle = WindowStyle.None;
}
SlaveWindow
using System.Windows.Forms;
public SlaveWindow(int screenPosition)
{
// Initailize
this.InitializeComponent();
// 指定螢幕
if (Screen.AllScreens.Length >= (screenPosition + 1))
{
Screen screen = Screen.AllScreens[screenPosition];
System.Drawing.Rectangle r1 = screen.WorkingArea;
this.Top = r1.Top;
this.Left = r1.Left;
// Normal Window
this.WindowState = WindowState.Normal;
this.Left = screen.WorkingArea.Left;
this.Top = screen.WorkingArea.Top;
this.Width = screen.WorkingArea.Width;
this.Height = screen.WorkingArea.Height;
}
// DataContext
this.DataContext = new CustomerWindowModel();
}
在SlaveWindow的Constructor中指定視窗為普通大小(WindowState.Normal),直到Load事件發生,才將視窗放大