Skysmith
Skysmith

Reputation: 29

Keep a MenuItem's IsChecked property synced with a bool

I have a simple WPF Application that has a menu on top. I want to add an option to make the main window to stay on top of other windows.

I created a bool named setTopMost in Property > Settings tab for users to save this setting. So, the setting will be remembered even after the app is terminated.

Everything is working as intended, I can click on the option or use the shortcut of Ctrl+T to make the window to stay on top, but I cannot get a check mark to appear next to the option when the window is on top of other windows.

I've read several articles regarding binding IsChecked to a bool, but I could not solve this problem on my own.

Here are my codes.

MainWindow.xaml

<Window.InputBindings>
    <KeyBinding Gesture="Ctrl+T" Command="{Binding TopMostCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Window.InputBindings>
<MenuItem Header="_Options">
    <MenuItem x:Name="Menu_AlwaysOnTop" Header="Always On _Top" IsCheckable="True" IsChecked="{Binding isTopMost}" Command="{Binding TopMostCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" InputGestureText="Ctrl+T" />
</MenuItem>

MainWindow.xaml.cs

namespace WPF_Practice
{
    public partial class MainWindow : Window
    {
        public bool isTopMost;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = new PracticeDataContext();
        }


        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            isTopMost = Properties.Settings.Default.setTopMost;
            Topmost = Properties.Settings.Default.setTopMost;
        }
    }

    public class PracticeDataContext
    {
        public ICommand TopMostCommand { get; } = new TopMostCommand();
    }

    public class TopMostCommand : ICommand
    {
        public void Execute(object parameter)
        {
            var TopMostClass = new MainWindow();
            TopMostClass.WindowTopMost();
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }
    }

}

Please mind that I am doing this as a hobby and quite new to this.

Upvotes: 0

Views: 103

Answers (1)

Keithernet
Keithernet

Reputation: 2509

The main reason why your MenuItem isn't updating properly is because you set the DataContext of the Window to PracticeDataContext.

public MainWindow()
{
    InitializeComponent();
    DataContext = new PracticeDataContext(); <--
}

This means that your bindings in MainWindow.xaml are going to be looking for properties in PracticeDataContext.

In this case you would want to have an IsTopMost property in your PracticeDataContext class in order for the binding to work.

Since IsTopMost isn't set until the Loaded event handler fires, you should implement INotifyPropertyChanged in your PracticeDataContext class so that your IsTopMost binding will get notified when it is set from settings.

A quick search on INotifyPropertyChanged will show you lots of examples. It's pretty easy.

Upvotes: 1

Related Questions