I bound the "WindowState" property of my main window to my ViewModel in order to change the state of the window by a command, but the first time I minimize the window it minimizes like a worksheet does in an Excel file. Is there a work around for this or a correct way to bind the "WindowState" property to my ViewModel so that the window minimizes correctly?
-
2What do you have so far? Post some code. – decyclone Jan 12 '11 at 16:44
-
4Without knowing the background of what you're trying to do, it sounds like you may be taking the ViewModel thing a step too far. Things that are strictly UI logic are completely acceptable in code-behind and in fact have no business in the ViewModel. I would say this includes things like focus and window state. – Josh Jan 12 '11 at 16:48
-
@Josh Enstein I switch to using the code behind like you said, now it works perfectly. What I'm trying to do is hide the taskbar button when the window is minimized and use a menu item attached to the taskbar icon to bring the window back. – Nick O Jan 12 '11 at 17:00
-
1I figured out what was causing the window to minimize like an Excel spreadsheet. If the property "ShowInTaskBar" is set to false before the window is minimized you get that reaction. If "ShowInTaskBar" is set after then it looks like it minimized to the system tray. I should have mentioned I was changing that property as well in the question. – Nick O Jan 14 '11 at 15:01
4 Answers
this is a sample work around that tested with Relaying Command Logic. You will get more detail on WPF Apps With The Model-View-ViewModel Design Pattern .
<Window x:Class="WpfMvvmTestCSharp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfMvvmTestCSharp"
Title="Window1" Height="300" Width="300" WindowState="{Binding CurWindowState, Mode=TwoWay}">
<Window.DataContext>
<vm:Window1ViewModel/>
</Window.DataContext>
<Grid>
<Button Command="{Binding CmdMax}" Height="23" Margin="12,25,0,0" Name="button1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="75">Maximize</Button>
<Button Command="{Binding CmdMin}" Height="23" Margin="101,25,102,0" Name="button2" VerticalAlignment="Top">Minimize</Button>
<Button Command="{Binding CmdRes}" Height="23" HorizontalAlignment="Right" Margin="0,25,13,0" Name="button3" VerticalAlignment="Top" Width="75">Restore</Button>
</Grid>
</Window>
and in the Windows ViewModel
class Window1ViewModel:ViewModelBase
{
public Window1ViewModel()
{
CurWindowState = WindowState.Maximized;
}
public ICommand CmdMax
{
get { return new RelayCommand(param => onCmdMax()); }
}
void onCmdMax()
{
CurWindowState = WindowState.Maximized;
}
public ICommand CmdMin
{
get { return new RelayCommand(param => onCmdMin()); }
}
void onCmdMin()
{
CurWindowState = WindowState.Minimized;
}
public ICommand CmdRes
{
get { return new RelayCommand(param => onCmdRes()); }
}
void onCmdRes()
{
CurWindowState = WindowState.Normal;
}
private WindowState _curWindowState;
public WindowState CurWindowState
{
get
{
return _curWindowState;
}
set
{
_curWindowState = value;
base.OnPropertyChanged("CurWindowState");
}
}
}

- 6,445
- 3
- 30
- 40
I don't think you should care about the window state in a view model, it's completely wrong because a lower-level layer is aware of a higher-level layer (thus wrong Separation of Concerns (SOC)).
What I normally do in this case is subscribe to changes in the view model from the code-behind of the control or window (thus the view) containing the view model. In this case, it is valid to write code in the code-behind because it is only used in the view (and thus the code-behind is the perfect location for this logic, which you really don't want to unit test).

- 5,689
- 1
- 18
- 32
-
5While this is generally true, it's also possible for the view model to expose a property unrelated to `WindowState` that should dictate its value. For example, one of my view models contained the Boolean `ShowResults`. I wanted this to toggle my `WindowState` to `Maximize`, so I created a BoolToWindowStateConverter. – Pakman Oct 20 '14 at 21:21
Another option to consider is subscribing both via a command AND an event to code behind, e.g:
<Button Command="{Binding SnoozeCommand}" Click="Button_Click">Snooze</Button>
The command in this case affects the VM. The Click event, only changes the Window state.

- 12,397
- 9
- 72
- 94
I have found my own solution which is perfectly suited to MVVM. I'm using behavior to find the parent window of the user control and track WindowState changes.
public class WindowStateBehavior : Behavior<UserControl>
{
public static readonly DependencyProperty WindowStateProperty =
DependencyProperty.Register(nameof(WindowState), typeof(WindowState), typeof(WindowStateBehavior),
new FrameworkPropertyMetadata(default(WindowState), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
private Window window;
public WindowState WindowState
{
get => (WindowState) GetValue(WindowStateProperty);
set => SetCurrentValue(WindowStateProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
this.window = Window.GetWindow(this.AssociatedObject)!;
this.window.StateChanged += this.OnStateChanged;
}
private void OnStateChanged(object sender, EventArgs e) => this.WindowState = this.window.WindowState;
}
This behavior can be used in any UserControl like this with bound WindowState in ViewModel.
<UserControl x:Class="RCBase.WPF.Monitor.CustomUserView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:RCBase.WPF.Behaviors"
mc:Ignorable="d" d:DataContext="{d:DesignInstance monitor:CustomUserViewModel}">
<i:Interaction.Behaviors>
<behaviors:WindowStateBehavior WindowState="{Binding WindowState}" />
</i:Interaction.Behaviors>

- 565
- 1
- 8
- 21