質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

3703閲覧

[WPF] MVVM Windowの動的な最大化・最小化・閉じるボタンの非アクティブ化

Base

総合スコア28

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2021/11/24 05:50

編集2021/11/24 05:56

前提・実現したいこと

WPFのWindowスタイル「閉じる・最大化・最小化」を動的に非アクティブ or 非表示にしたいと考えています。よろしくお願いいたします。

下記のサイトをベースに、ビヘイビアを使用してボタンを押した際に切り替える予定です。
https://b.amberfrog.net/post/88379654924/window-behavior

コードを見てみると、WinAPIのWM_SYSCOMMANDの値にて、切り替えているように考えたのですが、最大化・最小化の値を指定しても、「閉じる」同様非アクティブになりません。

自分の理解が違っているのでしょうか。。
よろしくお願いいたします。

発生している問題・エラーメッセージ

サンプルコード通りの「閉じる」は非アクティブにできるが、最大化・最小化の非アクティブ化が出来ない

該当のソースコード

CloseButtonBehavior

C#

1 2 [DllImport("user32.dll")] 3 private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 4 5 [DllImport("user32.dll")] 6 private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable); 7 8 private const uint SC_CLOSE = 0xF060; 9 private const uint SC_MAXIMIZE = 0xF030; //最大化 10 private const uint SC_MINIMIZE = 0xF020; //最小化 11 12 private const uint MF_BYCOMMAND = 0x00000000; 13 private const uint MF_GRAYED = 0x00000001; 14 private const uint MF_ENABLED = 0x00000000; 15 16 public static readonly DependencyProperty IsWindowCloseProperty = DependencyProperty.Register( 17 "IsWindowCloseEnable", typeof(bool), typeof(CloseButtonBehavior), new PropertyMetadata(true, new PropertyChangedCallback(OnPropertyChanged))); 18 19 public bool IsWindowCloseEnable 20 { 21 get { return (bool)this.GetValue(IsWindowCloseProperty); } 22 set { this.SetValue(IsWindowCloseProperty, value); } 23 } 24 25 private static void OnPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 26 { 27 var self = obj as CloseButtonBehavior; 28 if (self != null) 29 { 30 self.Apply(); 31 } 32 } 33 34 private void Apply() 35 { 36 if (AssociatedObject == null) 37 { 38 return; 39 } 40 var hwnd = new WindowInteropHelper(AssociatedObject).Handle; 41 IntPtr hMenu = GetSystemMenu(hwnd, false); 42 if (hMenu != IntPtr.Zero) 43 { 44 if (IsWindowCloseEnable) 45 { 46 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); 47 EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);//追記した(最大化ボタンのつもり) 48 EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);//追記した(最小化ボタンのつもり) 49 } 50 else 51 { 52 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED); 53 EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);//追記した(最大化ボタンのつもり) 54 EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED);//追記した(最小化ボタンのつもり) 55 } 56 } 57 }

xaml

1<Window x:Class="CloseButtonBehavior.Views.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 5 xmlns:b="clr-namespace:CloseButtonBehavior.Behaviors" 6 Title="Close Button Behavior Sample" 7 Height="80" Width="400"> 8 <i:Interaction.Behaviors> 9 <b:CloseButtonBehavior IsWindowCloseEnable="{Binding ElementName=CloseCheck, Path=IsChecked}"/> 10 </i:Interaction.Behaviors> 11 <Grid> 12 <CheckBox x:Name="CloseCheck" 13 Content="閉じるボタンを有効にする" 14 IsChecked="True" 15 VerticalAlignment="Center"/> 16 </Grid> 17</Window>

試したこと

Win32 APIの値を調査
https://docs.microsoft.com/en-us/windows/win32/menurc/wm-syscommand

補足情報(FW/ツールのバージョンなど)

環境:VisualStudio2019 pro
OS:Windows10

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

(歴史的経緯により)最小化・最大化は、SetWindowLongしてください。

How do I enable and disable the minimize, maximize, and close buttons in my caption bar? - The Old New Thing

WPF: Disabling or Hiding the Minimize, Maximize or Close Button Of a Window - TechNet Articles - United States (English) - TechNet Wiki

コードも書いてみようと思ったんですが、ちゃんとやろうとすると時間がかかりそうなので取り急ぎ情報だけ^^;

参考コードは最初からfalseだった時の手当てがないですね。


個別設定できたほうが一般向けだろうと思うので3つに分けました(一括切り替えも用意しようかとも思いましたが、バインドするとなると煩雑なので省略)

NuGet Gallery | Microsoft.Windows.CsWin32 0.1.619-beta
NuGet Gallery | Microsoft.Xaml.Behaviors.Wpf 1.1.39

xml

1<Window 2 x:Class="Questions370772.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:Behaviors="http://schemas.microsoft.com/xaml/behaviors" 6 xmlns:local="clr-namespace:Questions370772" 7 Width="800" 8 Height="450"> 9 <Behaviors:Interaction.Behaviors> 10 <local:WindowButtonBehavior 11 CloseButtonEnabled="{Binding IsChecked, ElementName=close}" 12 MaximizeButtonEnabled="{Binding IsChecked, ElementName=maximize}" 13 MinimizeButtonEnabled="{Binding IsChecked, ElementName=minimize}" /> 14 </Behaviors:Interaction.Behaviors> 15 16 <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> 17 <CheckBox 18 x:Name="minimize" 19 VerticalContentAlignment="Center" 20 Content="最小化ボタンを有効にする" /> 21 <CheckBox 22 x:Name="maximize" 23 VerticalContentAlignment="Center" 24 Content="最大化ボタンを有効にする" /> 25 <CheckBox 26 x:Name="close" 27 VerticalContentAlignment="Center" 28 Content="閉じるボタンを有効にする" /> 29 </StackPanel> 30</Window>

cs

1using System; 2using System.Windows; 3using System.Windows.Interop; 4using Microsoft.Xaml.Behaviors; 5using Windows.Win32.Foundation; 6 7using static Windows.Win32.PInvoke; 8using static Windows.Win32.UI.WindowsAndMessaging.MENU_ITEM_FLAGS; 9using static Windows.Win32.UI.WindowsAndMessaging.WINDOW_LONG_PTR_INDEX; 10using static Windows.Win32.UI.WindowsAndMessaging.WINDOW_STYLE; 11 12namespace Questions370772 13{ 14 public class WindowButtonBehavior : Behavior<Window> 15 { 16 public bool MinimizeButtonEnabled { get => (bool)GetValue(MinimizeButtonEnabledProperty); set => SetValue(MinimizeButtonEnabledProperty, value); } 17 public static readonly DependencyProperty MinimizeButtonEnabledProperty 18 = DependencyProperty.Register(nameof(MinimizeButtonEnabled), typeof(bool), typeof(WindowButtonBehavior), 19 new PropertyMetadata(true, new PropertyChangedCallback(OnMinimizeButtonEnabledChanged))); 20 private static void OnMinimizeButtonEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 21 => (d as WindowButtonBehavior)?.OnMinimizeButtonEnabledChanged(); 22 23 public bool MaximizeButtonEnabled { get => (bool)GetValue(MaximizeButtonEnabledProperty); set => SetValue(MaximizeButtonEnabledProperty, value); } 24 public static readonly DependencyProperty MaximizeButtonEnabledProperty 25 = DependencyProperty.Register(nameof(MaximizeButtonEnabled), typeof(bool), typeof(WindowButtonBehavior), 26 new PropertyMetadata(true, new PropertyChangedCallback(OnMaximizeButtonEnabledChanged))); 27 private static void OnMaximizeButtonEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 28 => (d as WindowButtonBehavior)?.OnMaximizeButtonEnabledChanged(); 29 30 public bool CloseButtonEnabled { get => (bool)GetValue(CloseButtonEnabledProperty); set => SetValue(CloseButtonEnabledProperty, value); } 31 public static readonly DependencyProperty CloseButtonEnabledProperty 32 = DependencyProperty.Register(nameof(CloseButtonEnabled), typeof(bool), typeof(WindowButtonBehavior), 33 new PropertyMetadata(true, new PropertyChangedCallback(OnCloseButtonEnabledChanged))); 34 private static void OnCloseButtonEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 35 => (d as WindowButtonBehavior)?.OnCloseButtonEnabledChanged(); 36 37 38 private IntPtr hwnd; 39 40 protected override void OnAttached() 41 => AssociatedObject.SourceInitialized += AssociatedObject_SourceInitialized; 42 43 private void AssociatedObject_SourceInitialized(object? sender, EventArgs e) 44 { 45 AssociatedObject.SourceInitialized -= AssociatedObject_SourceInitialized; 46 47 hwnd = new WindowInteropHelper(AssociatedObject).Handle; 48 49 if (!MinimizeButtonEnabled) OnMinimizeButtonEnabledChanged(); 50 if (!MaximizeButtonEnabled) OnMaximizeButtonEnabledChanged(); 51 if (!CloseButtonEnabled) OnCloseButtonEnabledChanged(); 52 } 53 54 private void OnMinimizeButtonEnabledChanged() 55 { 56 if (hwnd == IntPtr.Zero) return; 57 58 if (MinimizeButtonEnabled) 59 { 60 SetWindowLong((HWND)hwnd, GWL_STYLE, GetWindowLong((HWND)hwnd, GWL_STYLE) | (int)WS_MINIMIZEBOX); 61 } 62 else 63 { 64 SetWindowLong((HWND)hwnd, GWL_STYLE, GetWindowLong((HWND)hwnd, GWL_STYLE) & ~(int)WS_MINIMIZEBOX); 65 //if (AssociatedObject.WindowState == WindowState.Minimized) 66 //{ 67 // AssociatedObject.WindowState = WindowState.Normal; 68 //} 69 } 70 } 71 72 private void OnMaximizeButtonEnabledChanged() 73 { 74 if (hwnd == IntPtr.Zero) return; 75 76 if (MaximizeButtonEnabled) 77 { 78 SetWindowLong((HWND)hwnd, GWL_STYLE, GetWindowLong((HWND)hwnd, GWL_STYLE) | (int)WS_MAXIMIZEBOX); 79 } 80 else 81 { 82 SetWindowLong((HWND)hwnd, GWL_STYLE, GetWindowLong((HWND)hwnd, GWL_STYLE) & ~(int)WS_MAXIMIZEBOX); 83 //if (AssociatedObject.WindowState == WindowState.Maximized) 84 //{ 85 // AssociatedObject.WindowState = WindowState.Normal; 86 //} 87 } 88 } 89 90 private void OnCloseButtonEnabledChanged() 91 { 92 if (hwnd == IntPtr.Zero) return; 93 94 var hMenu = GetSystemMenu((HWND)hwnd, false); 95 if (hMenu != IntPtr.Zero) 96 { 97 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (CloseButtonEnabled ? MF_ENABLED : MF_GRAYED)); 98 } 99 } 100 } 101 102 public partial class MainWindow : Window 103 { 104 public MainWindow() => InitializeComponent(); 105 } 106}

txt:NativeMethods.txt

1EnableMenuItem 2GetSystemMenu 3GetWindowLong 4SetWindowLong 5SC_CLOSE 6WS_MAXIMIZEBOX 7WS_MINIMIZEBOX

最小化・最大化両方禁止した場合は、ボタン自体が消える(Windowsがそういう仕様)
すでに最大化(最小化)されている状態で、最大化(最小化)を禁止した場合元に戻るべきかどうか。

2つ目のリンクではmenuHandleを使いまわし最後にDestroyMenuしろと言っているが、都度取得しないと動作しなかった。`

投稿2021/11/24 12:19

編集2023/07/29 09:04
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Base

2021/11/24 23:17

情報、ありがとうございます。 確認させていただき、コードも進めたいと思います。
Base

2021/12/01 23:46

回答ありがとうございます。 動作確認をするタイミングが遅くなってしまい、ベストアンサー遅れました。申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問