How to bring a window to the foreground using wpf and using mvvm

I have a window that essentially starts a timer. When the timer reaches 0, I want the window to be in front, so that it is visible and does not hide behind another application.

From what I can assemble, I would just call window.activate () to accomplish this, but with mvvm my view model does not have a window reference.

+4
source share
3 answers

You can do this in several ways - adding a link to a window may work because the view model is not related to the view, but is related to it, but I don't really like this approach, since it pretty much matches your viewmodel - actually this is not the point of MVVM

A better approach might be to have your viewmodel raise an event or command that the view can handle. So the view decides which UI action is associated with the command / event

eg. just

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

Of course, how you do this is up to you, but I will probably try to execute routable commands.

Edit: you cannot β€œbind” a simple event, since it is called from the viewmodel.

A simple event-based example is simply to add an event to the viewmodel and process it directly ... for example. imagine the next MainWindow with the ViewModel property

 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); } } 

Then ViewModel can just fire the event:

 // 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 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 will be:

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

Thus, the button invokes a command, which, in turn, fires an event that processes the view (MainWindow) and displays a message. Thus, the view / user interface decides on the course of action based on the type of event raised. Of course, it could be your timer that triggered the event.

You can always take a more attractive route, for example, some answers to this question ...

How to close ViewModel form?

but honestly, it depends on whether you really need it - a simple event works well - some people overly complicate things for the sake of elegance, but to the detriment of simplicity and performance!

+2
source

A β€œpurist” MVVM solution should use behavior. The following is the behavior for Window with the Activated property. Setting the property to true activates the window (and restores it if minimized):

 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; } } 

Behavior requires a reference to System.Windows.Interactivity.dll . Fortunately, it is now available on NuGet in the Blend.Interactivity.Wpf package.

The behavior attaches to the window in XAML as follows:

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

The view model should display the boolean Activated property. Setting this property to true will activate the window (if it is not already activated). As an added bonus, it will also restore a minimized window.

+17
source

I would go as follows:

 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 { } 
0
source

All Articles