none
閉じるボタンを無効にしたい RRS feed

  • 質問

  • [Windows Vista Business]

    [C# 2.0 + .NET Framework 3.0]

     

    .NET 2.0のWinFormでは、CreateParamsをオーバーライドしてウィンドウの閉じるボタン[×]を無効にしていました。

    同じようにWPFのウィンドウでも閉じるボタンを無効にしたいのですが、CreateParamsメソッドがありません。

     

    WPFでは、何クラスの何メソッドをオーバーライドすれば良いのでしょうか?

     

    よろしくお願いします。

    2007年10月29日 8:42

回答

  • 以下を読む限り、ちょっと難しそうですね。

     

    Disable/hide minimize button
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1

    2007年10月30日 5:53
    モデレータ
  • 従来のハンドルフックを使用してですが、閉じるボタンを無効&グレー化することが出来ました。

    既にどこかで出てるかもしれませんが、ソース置いておきます。

     

    ~【以下ソースコード】~

        public partial class Window1 : Window
        {
            [DllImport("user32.dll")]
            private static extern Window1 GetSystemMenu(Window1 hWnd, bool bRevert);
     
            [DllImport("user32.dll")]
            private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
            private const uint MF_BYCOMMAND = 0x00000000;
            private const uint MF_GRAYED = 0x00000001;
            private const uint MF_ENABLED = 0x00000000;
            private const uint SC_CLOSE = 0xF060;
            private const int WM_SHOWWINDOW = 0x00000018;
            private const int WM_SYSCOMMAND = 0x112;
            private const int WM_CLOSE = 0x10;
            private HwndSource hwndSource = null;
     
            public Window1()
            {
                InitializeComponent();
            }
            protected override void OnSourceInitialized(EventArgs e)
            {
                base.OnSourceInitialized(e);
     
                hwndSource = PresentationSource.FromVisual(this) as HwndSource;
                if (hwndSource != null)
                {
                    hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));
                }
            }
     
            private IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                if (msg == WM_SHOWWINDOW)
                {
                    IntPtr hMenu = GetSystemMenu(hwnd, false);
                    if (hMenu != IntPtr.Zero)
                    {
                        EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
                    }
                }
                else if (msg == WM_SYSCOMMAND && (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
                {
                    handled = true;
                }
                return IntPtr.Zero;
            }
        }
    2007年11月12日 4:12
  • hwndsource は,プライベートメンバとしてメソッドから出して,
    Window1 が閉じる前にちゃんと RemoveHook() しておいた方が

    (フック云々をきれいに終えるというより,
    HwndSourceのインスタンスがローカル変数でも,
    弱参照の関係でずっと残る仕組みになっているので,
    Window1インスタンスのwndprocへの参照を

    HwndSourceのインスタンスから取り除いておいた方が)
    コード的には安全側に倒れるんじゃないかと思います。

    MSDNブログのコードでも後始末をやってないので,なくてもいいのかもしれませんが...

     

     

    あと,

    HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
    if (hwndSource != null)

    って,

    HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
    if (hwndSource != null)

    ですよね。

    2007年11月12日 16:13

すべての返信

  • XBAP などの部分信頼で動くアプリとの関係で,
    Windowクラスとは別のクラスを仲介する形にしたんじゃないですかね。
    (例えば,下の FromHwnd などで (CAS で) UI Permission が必要になるなど)

     

    System.Windows.Interop 名前空間の

    WindowInteropHelper  (このコンストラクタにWPFのWindowインスタンスを渡してハンドルを取得できます。で,HwndSource.FromHwnd に Handle を渡して HwndSource もしくは,いきなり HwndSource.FromVisual で)

    ・ HwndSource (AddHook, RemoveHook, 弱参照の関係で OnClosedで Dispose もしておいた方が無難かも)

    などのクラスを介してやるんじゃないかと思います。
    (いわゆる従来のフックしてウィンドウメッセージを横取りする形)

    ひょっとしたら,簡単にやれる方法もあるのかもしれませんが。

     

    cf. フックする場所ですが,

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1390791&SiteID=7

    のようにするか,OnSourceInitialized をオーバーライドするか。

    2007年10月30日 2:12
  • ご返信ありがとうございます。

     

     稍丼 さんからの引用

    System.Windows.Interop 名前空間の

    WindowInteropHelper  (このコンストラクタにWPFのWindowインスタンスを渡してハンドルを取得できます。で,HwndSource.FromHwnd に Handle を渡して HwndSource もしくは,いきなり HwndSource.FromVisual で)

    ・ HwndSource (AddHook, RemoveHook, 弱参照の関係で OnClosedで Dispose もしておいた方が無難かも)

    などのクラスを介してやるんじゃないかと思います。
    (いわゆる従来のフックしてウィンドウメッセージを横取りする形)

    ひょっとしたら,簡単にやれる方法もあるのかもしれませんが。

     

    cf. フックする場所ですが,

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1390791&SiteID=7

    のようにするか,OnSourceInitialized をオーバーライドするか。

     

    提示していただいたURLを参考にしてみました。

    [×]ボタンを押してもウィンドウが閉じなくなったのですが、無効になっていません。

    やはり、無効にするにはAPI関数を使うしかないのでしょうか。

     

    -----[ 以下ソースコード ]-------------------------------------------------------------------------------------------

        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();

            }

     

            protected override void OnSourceInitialized(EventArgs e)
            {
                HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
                hwndSource.AddHook(Hook);

     

                base.OnSourceInitialized(e);

            }

     

            private const int WM_SYSCOMMAND = 0x112;
            private const int SC_CLOSE      = 0xF060;

     

            private static IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                if (msg == WM_SYSCOMMAND &&  (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
                {
                    handled = true;
                }

                return IntPtr.Zero;
            }
        }

    2007年10月30日 5:03
  • 以下を読む限り、ちょっと難しそうですね。

     

    Disable/hide minimize button
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1

    2007年10月30日 5:53
    モデレータ
  • CreateParams をオーバーライドしたときのような

    完璧な感じに...という風には行かないですね。

    2007年10月30日 7:00
  • 試す時間がないんですが,
    HwndSource を HwndSourceParameters で作成して,
    RootVisual に Page を指定などではやれないんですかね...

    2007年10月30日 7:38
  • trapemiya様、稍丼様ご回答ありがとうござます。

     

     trapemiya さんからの引用

    以下を読む限り、ちょっと難しそうですね。

     

    Disable/hide minimize button
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1

     

    上記URL内にあったブログhttp://pavanpodila.spaces.live.com/のサンプルを見ました。

    WPFのWindowクラスは、やはり継承されるクラスがWinFormとは違うので、単純にオーバーライドするだけでは難しいようですね。サンプルのようにオリジナルでタイトルバーごとオーナードローすれば大丈夫そうですが、まだまだWPFに未熟なので今回はもう少し様子を見てみます。

    2007年10月31日 8:30
  • 従来のハンドルフックを使用してですが、閉じるボタンを無効&グレー化することが出来ました。

    既にどこかで出てるかもしれませんが、ソース置いておきます。

     

    ~【以下ソースコード】~

        public partial class Window1 : Window
        {
            [DllImport("user32.dll")]
            private static extern Window1 GetSystemMenu(Window1 hWnd, bool bRevert);
     
            [DllImport("user32.dll")]
            private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
            private const uint MF_BYCOMMAND = 0x00000000;
            private const uint MF_GRAYED = 0x00000001;
            private const uint MF_ENABLED = 0x00000000;
            private const uint SC_CLOSE = 0xF060;
            private const int WM_SHOWWINDOW = 0x00000018;
            private const int WM_SYSCOMMAND = 0x112;
            private const int WM_CLOSE = 0x10;
            private HwndSource hwndSource = null;
     
            public Window1()
            {
                InitializeComponent();
            }
            protected override void OnSourceInitialized(EventArgs e)
            {
                base.OnSourceInitialized(e);
     
                hwndSource = PresentationSource.FromVisual(this) as HwndSource;
                if (hwndSource != null)
                {
                    hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));
                }
            }
     
            private IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                if (msg == WM_SHOWWINDOW)
                {
                    IntPtr hMenu = GetSystemMenu(hwnd, false);
                    if (hMenu != IntPtr.Zero)
                    {
                        EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
                    }
                }
                else if (msg == WM_SYSCOMMAND && (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
                {
                    handled = true;
                }
                return IntPtr.Zero;
            }
        }
    2007年11月12日 4:12
  • hwndsource は,プライベートメンバとしてメソッドから出して,
    Window1 が閉じる前にちゃんと RemoveHook() しておいた方が

    (フック云々をきれいに終えるというより,
    HwndSourceのインスタンスがローカル変数でも,
    弱参照の関係でずっと残る仕組みになっているので,
    Window1インスタンスのwndprocへの参照を

    HwndSourceのインスタンスから取り除いておいた方が)
    コード的には安全側に倒れるんじゃないかと思います。

    MSDNブログのコードでも後始末をやってないので,なくてもいいのかもしれませんが...

     

     

    あと,

    HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
    if (hwndSource != null)

    って,

    HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
    if (hwndSource != null)

    ですよね。

    2007年11月12日 16:13