Elsassmania
Elsassmania

Reputation: 175

How to restore minimized/hidden window?

I have MaterialWindows from MaterialDesignInXaml which can be minimized in the notification bar.

I hide the windows by setting the Visibility to Collapsed.

The double click on the icon launches a command to restore the windows:

public RelayCommand OpenWindowsCommand => new RelayCommand(ExecuteOpenWindowsCommand);
private void ExecuteOpenWindowsCommand(object o)
{
    WindowState = WindowState.Normal;
    //Activated = true;
    //IsInForeground = true;
    //IsInForeground = false;
    //IsFocus = true;
}

My property WindowState changed the visibility in it and notify the change with OnPropertyChanded.

The windows appear in the task bar but doesn't come on the foreground of my screen.

As you can see in comment, I tried different ways to get it without success like :

Is there something special to put a windows in the foreground of the screen?

Edit to add a sample repo :

MainWindow.xaml

<controls:MaterialWindow
    x:Class="MinimiedWindows.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Behaviors="clr-namespace:MinimiedWindows.Behavior"
    xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:MinimiedWindows"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:tb="http://www.hardcodet.net/taskbar"
    Title="MainWindow"
    Width="800"
    Height="450"
    Focusable="{Binding IsFocus}"
    Icon="app.ico"
    Topmost="{Binding IsFocus}"
    Visibility="{Binding WindowsVisibility, Mode=TwoWay}"
    WindowState="{Binding WindowState}"
    mc:Ignorable="d">

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

    <Grid>
        <tb:TaskbarIcon
            x:Name="myNotifyIcon"
            DoubleClickCommand="{Binding OpenWindowsCommand}"
            IconSource="{Binding NotifyIcon}"
            MenuActivation="LeftOrRightClick"
            PopupActivation="DoubleClick"
            ToolTip="aa"
            Visibility="{Binding NotifyIconVisibility}" />
    </Grid>
</controls:MaterialWindow>

MainWindows constructor set the datacontext to a new MainViewModel.

MainViewModel.cs : (ViewModelBase is the classic one with the property OnPropertyChanged)

public class MainViewModel : ViewModelBase
{
   public MainViewModel()
   {
   }

   #region Windows properties

   private WindowState _WindowState = WindowState.Normal;

   public WindowState WindowState
   {
      get { return _WindowState; }
      set
      {
         _WindowState = value;
         OnPropertyChanged();
         OnPropertyChanged("WindowsVisibility");
         OnPropertyChanged("NotifyIconVisibility");
      }
   }

   private Visibility _WindowsVisibility = Visibility.Visible;

   public Visibility WindowsVisibility
   {
      get
      {
         if (WindowState == WindowState.Minimized)
         {
            return Visibility.Collapsed;
         }

         return Visibility.Visible;
      }
      set { _WindowsVisibility = value; }
   }

   private bool _Activated;

   public bool Activated
   {
      get { return _Activated; }
      set
      {
         _Activated = value;
         OnPropertyChanged();
      }
   }

   private bool _IsInForeground;

   public bool IsInForeground
   {
      get { return _IsInForeground; }
      set
      {
         _IsInForeground = value;
         OnPropertyChanged();
      }
   }

   private bool _IsFocus;

   public bool IsFocus
   {
      get { return _IsFocus; }
      set
      {
         _IsFocus = value;
         OnPropertyChanged();
      }
   }

   #endregion

   #region NotifyBar

   public string NotifyIcon
   {
      get { return "app.ico"; }
   }

   public Visibility NotifyIconVisibility
   {
      get
      {
         if (WindowState == WindowState.Minimized)
         {
            return Visibility.Visible;
         }

         return Visibility.Collapsed;
      }
   }

   public RelayCommand OpenWindowsCommand => new RelayCommand(ExecuteOpenWindowsCommand);
   private void ExecuteOpenWindowsCommand(object o)
   {
      WindowState = WindowState.Normal;
      Activated = true;
   }
   #endregion
}

And finally my ActivateBehavior.cs

public class ActivateBehavior : Behavior<MaterialWindow>
{
   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;
   }
}

For the packages, I have installed Hardcodet.NotifyIcon.Wpf, MaterialDesignExtensionss 3.1.0 (and the materialDesign dependencies) and System.Windows.Interactivity.WPF.

Upvotes: 0

Views: 1022

Answers (1)

thatguy
thatguy

Reputation: 22119

Change your ExecuteOpenWindowsCommand to only set the Activated property.

private void ExecuteOpenWindowsCommand()
{
   Activated = true;
}

Adapt the OnActivatedChanged method in the ActivateBehavior like this.

private 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.
   var window = behavior.AssociatedObject;
   if (window.WindowState == WindowState.Minimized)
   {
      window.WindowState = WindowState.Normal;
      SystemCommands.RestoreWindow(window);
   }

   window.Activate();
}

The essential part is restoring the window, which did not happen before, it was hidden. Then it needs to be activated to come to foreground. The window state asssignment is not needed, but makes the restore transition of the window more pleasant.

Upvotes: 1

Related Questions