Search code examples
wpfbindinguser-controlsicommand

WPF Bind WindowState to Command in UserControl


I am attempting to make a customised title bar for use in WPF applications, partly in order to learn / practice using usercontrols. I have done what I believe I need to do to bind a command in the usercontrol view model to a property (windowstate) of the mainwindow and the press of a button, but although the command is executing when the button is pressed, the windowstate of the mainwindow containing the usercontrol does not change.

Is there something that I have not understood about the binding here? I feel like I have followed all the instructions I could find online to the letter! (obviously I have not)

Here's the usercontrol xaml:

<UserControl x:Class="UserControls.TitleBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:vm="clr-namespace:ViewModels"
             mc:Ignorable="d">
    <UserControl.DataContext>
        <vm:TitleBar_ViewModel/>
    </UserControl.DataContext>
    <Button Command="{Binding MaximiseCommand}" />
</UserControl>

and the code in the viewmodel looks like this:

namespace ViewModels
{
    public class TitleBar_ViewModel : DependencyObject, INotifyPropertyChanged
    {
        public TitleBar_ViewModel() { }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        private WindowState _windowState;
        public WindowState WindowState
        {
            get
            { return _windowState; }
            set
            {
                _windowState = value;
                OnPropertyChanged();
            }
        }

        private ICommand _maximiseCommand;

        public ICommand MaximiseCommand
        {
            get
            {
                if (_maximiseCommand == null)
                {
                    _maximiseCommand = new RelayCommand(param => this.Maximise(), param => true);
                }
                return _maximiseCommand;
            }
        }
        private void Maximise()
        {
            WindowState = WindowState.Maximized;
        }
    }
}

The xaml for the mainwindow that uses the usercontrol is as follows:

<Window x:Class="Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:uc="clr-namespace:UserControls;assembly=UserControls"
        mc:Ignorable="d"
        WindowState="{Binding WindowState,ElementName=Titlebar}">
    <Grid>
        <uc:TitleBar x:Name="Titlebar"/>
    </Grid>
</Window>

I've kept things as simple as I possibly can for this demonstration so hopefully you are able to give some pointers as to some essential part of the build process that I have missed, that causes the mainwindow windowstate to be unaffected by the button press.

Any pointers will be great; this use of user controls is really throwing me and I really want to start using it to avoid replicating code over and again for each application!


Solution

  • Your Usercontrol has no WindowState property, but the DataContext of it. So:

    WindowState="{Binding DataContext.WindowState,ElementName=Titlebar}"