2012-08-13 53 views
4

我有一個本質上運行計時器的窗口。當計時器達到0時,我想將窗口放在前面,以便它可見並且不會隱藏在某個其他應用程序的後面。如何將窗口與wpf和使用mvvm

從我可以收集,我只想叫window.activate()來實現這一點,但與MVVM我的視圖模型不具有窗口的引用。

回答

2

你可以去了解它在幾個方面 - 增加了窗口的引用可能會起作用,因爲視圖模型不再加看法,但與此相關的,但我真的不喜歡,因爲它這種做法非常做夫妻您以您的視圖模型 - 這是不是真的MVVM

點一個更好的辦法可能是讓你的視圖模型引發一個事件或視圖可以處理的命令。這樣的觀點得到決定什麼UI動作與命令相關聯/事件

例如簡單地

class SomeView 
{ 
    void HandleSomeCommandOrEvent() 
    { 
     this.Activate(); 
    } 
} 

當然,你怎麼這樣組裝起來是你的,但我可能會嘗試並獲得路由命令發生

編輯:你不能真正「綁定」一個簡單的事件,因爲它是從視圖模型調用。

一個簡單的基於事件的例子就是將事件添加到視圖模型,並直接處理它...例如想象一下以下主窗口與視圖模型屬性

public partial class MainWindow : Window 
{ 
    MainWindowViewModel ViewModel { get; set; } 

    public MainWindow() 
    { 
     InitializeComponent(); 

     ViewModel = new MainWindowViewModel(); 
     ViewModel.ShowMessage += ViewModel_ShowMessage; 
     this.DataContext = ViewModel; 
    } 

    void ViewModel_ShowMessage(object sender, ShowMessageEventArgs e) 
    { 
     MessageBox.Show(e.Message, "Some caption", MessageBoxButton.OK); 
    } 

} 

然後視圖模型可以只觸發事件:

// The view model 
public class MainWindowViewModel 
{ 
    // The button click command 
    public RelayCommand ButtonClickCommand { get; set; } 

    // The event to fire 
    public event EventHandler<ShowMessageEventArgs> ShowMessage; 

    public MainWindowViewModel() 
    {    
     ButtonClickCommand = new RelayCommand(ButtonClicked);    
    } 

    void ButtonClicked(object param) 
    { 
     // This button is wired up in the view as normal and fires the event 
     OnShowMessage("You clicked the button"); 
    } 

    // Fire the event - it's up to the view to decide how to implement this event and show a message 
    void OnShowMessage(string message) 
    { 
     if (ShowMessage != null) ShowMessage(this, new ShowMessageEventArgs(message)); 
    } 
} 

public class ShowMessageEventArgs : EventArgs 
{ 
    public string Message { get; private set; } 

    public ShowMessageEventArgs(string message) 
    { 
     Message = message; 
    } 
} 

的XAML是:

<Button Command="{Binding ButtonClickCommand}">Click me!</Button> 

所以按鈕調用的命令,然後觸發視圖(MainWindow)處理並顯示消息框的事件。這樣,視圖/用戶界面根據引發的事件類型決定操作的過程。當然,也可能是你的計時器,它觸發事件

您可以隨時下井更多地參與途徑,如一些對這個問題的答案...

How should the ViewModel close the form?

但說實話,這取決於你是否真的需要它 - 一個簡單的事件效果很好 - 有些人爲了高雅而過分複雜,但卻不利於簡單和生產力!

+0

我學習WPF和綁定,所以這可能是一個簡單的問題。你如何將命令綁定到視圖?我正在做這個按鈕,但我不知道如何做到這一點沒有wpf控制

+0

添加更多信息 – Charleh 2012-08-13 21:26:24

17

「純粹」MVVM解決方案是使用一種行爲。以下是具有Activated屬性的Window的行爲。該屬性設置爲true,將激活窗口(如果它最小化還原):

public class ActivateBehavior : Behavior<Window> { 

    Boolean isActivated; 

    public static readonly DependencyProperty ActivatedProperty = 
    DependencyProperty.Register(
     "Activated", 
     typeof(Boolean), 
     typeof(ActivateBehavior), 
     new PropertyMetadata(OnActivatedChanged) 
    ); 

    public Boolean Activated { 
    get { return (Boolean) GetValue(ActivatedProperty); } 
    set { SetValue(ActivatedProperty, value); } 
    } 

    static void OnActivatedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { 
    var behavior = (ActivateBehavior) dependencyObject; 
    if (!behavior.Activated || behavior.isActivated) 
     return; 
    // The Activated property is set to true but the Activated event (tracked by the 
    // isActivated field) hasn't been fired. Go ahead and activate the window. 
    if (behavior.AssociatedObject.WindowState == WindowState.Minimized) 
     behavior.AssociatedObject.WindowState = WindowState.Normal; 
    behavior.AssociatedObject.Activate(); 
    } 

    protected override void OnAttached() { 
    AssociatedObject.Activated += OnActivated; 
    AssociatedObject.Deactivated += OnDeactivated; 
    } 

    protected override void OnDetaching() { 
    AssociatedObject.Activated -= OnActivated; 
    AssociatedObject.Deactivated -= OnDeactivated; 
    } 

    void OnActivated(Object sender, EventArgs eventArgs) { 
    this.isActivated = true; 
    Activated = true; 
    } 

    void OnDeactivated(Object sender, EventArgs eventArgs) { 
    this.isActivated = false; 
    Activated = false; 
    } 

} 

行爲要求System.Windows.Interactivity.dll參考。幸運的是,這現在可以在NuGet的Blend.Interactivity.Wpf包中找到。

行爲被附接到在XAML一個窗口這樣的:

<Window ...> 
    <i:Interaction.Behaviors> 
    <Behaviors:ActivateBehavior Activated="{Binding Activated, Mode=TwoWay}"/> 
    </i:Interaction.Behaviors> 

視圖模型應該暴露一個布爾Activated屬性。將該屬性設置爲true將激活該窗口(除非它已被激活)。作爲額外的獎勵,它還將恢復最小化的窗口。

+1

Thx Martin。這是真正的答案,而不是黑客行爲。 – 2013-01-18 16:30:51

+0

優秀的答案。 – 2013-10-22 06:20:31

+0

將'Activated'屬性設置爲'false'會發生什麼? – romanoza 2014-08-08 18:07:00

0

我會走這條路:

using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.Command;  
using GalaSoft.MvvmLight.Messaging; 

// View 

public partial class TestActivateWindow : Window 
{ 
    public TestActivateWindow() { 
     InitializeComponent(); 
     Messenger.Default.Register<ActivateWindowMsg>(this, (msg) => Activate()); 
    } 
} 

// View Model 

public class MainViewModel: ViewModelBase 
{ 
    ICommand _activateChildWindowCommand; 

    public ICommand ActivateChildWindowCommand { 
     get { 
      return _activateChildWindowCommand?? (_activateChildWindowCommand = new RelayCommand(() => { 
       Messenger.Default.Send(new ActivateWindowMsg()); 
     })); 
     } 
    } 
} 

public class ActivateWindowMsg 
{ 
}