ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 应用程序栏窗口远离停靠位置,然后移动到停靠位置

2019-05-20 09:01:55  阅读:219  来源: 互联网

标签:c window wpf taskbar


我最近在我的WPF应用程序中添加了一个窗口,它可以作为“应用栏”停靠在桌面的边缘.我用来进行对接的代码来自this stackoverflow帖子.

该程序有三个与此窗口相关的用户设置.一个是窗口停靠的边缘,另外两个是Left&的值.顶级物业.我们的想法是,当窗口关闭或程序关闭时,窗口将在程序重新启动时以相同的状态和位置打开.

我遇到的问题是,当程序打开时,窗口首先显示在屏幕上的随机位置(可能是创建窗口时由Windows分配给它的坐标),然后它移动到停靠位置.我见过的其他具有应用程序栏功能的程序,如Trillian,从头开始绘制在停靠位置.看到窗户像这样移动有点令人不安.

这是窗口中的一些代码:

private void AppBarWindow_Activated( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellActivated( this );
    }
}

private void AppBarWindow_Closing( object sender, CancelEventArgs e ) {
    Settings.Default.AppBarWindowLeft = Left;
    Settings.Default.AppBarWindowTop  = Top;
    Settings.Default.Save();

    AppBarFunctions.SetAppBar( this, ABEdge.None );

    // Other, app specific code . . .
}

private void AppBarWindow_LocationChanged( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellWindowPosChanged( this );
    }
}

private void AppBarWindow_SourceInitialized( object sender, EventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        SizeWindow( Settings.Default.AppBarWindowEdge == ABEdge.None ? ABEdge.Left : ABEdge.None );
    }
}

private void AppBarWindow_SizeChanged( object sender, SizeChangedEventArgs e ) {
    if ( Settings.Default.AppBarWindowEdge != ABEdge.None ) {
        AppBarFunctions.SendShellWindowPosChanged( this );
    }
}

private void SizeWindow( ABEdge originalEdge ) {
    // App specific code to compute the window's size . . .

    if ( originalEdge != Settings.Default.AppBarWindowEdge ) {
        AppBarFunctions.SetAppBar( this, Settings.Default.AppBarWindowEdge );
    }

    Settings.Default.AppBarWindowLeft = Left;
    Settings.Default.AppBarWindowTop  = Top;
    Settings.Default.Save();
}

我已经添加了函数来在激活窗口时调用SHAppBarrMessage,或者当它的位置和大小发生变化时,就像我在this中所读到的那样.调用似乎对行为没有任何影响,所以我可能会删除它们.

我知道在显示窗口之前调用SourceInitialized和Loading事件,但是在窗口句柄和布局之后调用它们.措施通行证已经完成.但是,看起来窗口是在调用AppBarFunctions.SetAppBar之前呈现的,这就是我看到它出现然后移动到位的原因.

我还尝试通过将Left和Top属性设置为窗口构造函数中设置中保存的值,将窗口移动到停靠位置.这也行不通.实际上,情况更糟,因为窗口首先被绘制在停靠位置,然后显然被移离桌面边缘以腾出空间,然后移回到停靠位置.

如何让这个窗口在启动时出现在停靠位置而不是之后移动?

编辑:

我想我找到了问题的原因.在AppetCarFoss类代码中,在ABSetPos方法中有一个注释,就在它调度窗口的Dispatcher(UI线程)上的DoResize方法调用之前.评论内容如下:

// This is done async, because WPF will send a resize after a new appbar is added.  
// if we size right away, WPFs resize comes last and overrides us.

显然,WPF或Windows正在将窗口移出为窗口保留的空间,然后我将其移回.我在代码中添加了许多跟踪点.我可以看到窗口在移动之后才会被渲染(代码中的注释中提到的那个).渲染窗口后,我的代码将其移动到停靠位置.

AppBarFunctions类已经添加了一个窗口过程挂钩,用于监视来自shell的消息.如果我为WM_WINDOWPOSCHANGED添加一个检查,我能否以某种方式阻止消息被处理?或者我可以更改Windows / WPF完成的移动的Left和Top属性的值,以便窗口最终到达我想要的位置?

解决方法:

我找到了一种方法来阻止窗户从停靠区域移动.基本上,我正在使用的代码已经使用Window Procedure Hook方法来监视ABN_ *通知消息.我在此方法中添加了代码以监视WM_WINDOWPOSCHANGING消息.

这是我写的代码:

public IntPtr WindowProcedureHook( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) {
    if ( msg == (int) WinMessages.WM_WINDOWPOSCHANGING ) {
        if ( IsDocked && !IsDragging ) {
            WindowPos pos = (WindowPos) Marshal.PtrToStructure( lParam, typeof( WindowPos ) );

            // Keep this window in its docked position.
            pos.x  = (int) DockedPosition.X;
            pos.y  = (int) DockedPosition.Y;
            pos.cx = (int) DockedSize.Width;
            pos.cy = (int) DockedSize.Height;

            Marshal.StructureToPtr( pos, lParam, false );
            handled = true;
        }

    } else if ( msg == CallbackId ) {
        if ( wParam.ToInt32() == (int) ABNotify.ABN_WINDOWPOSCHANGED ) {
            SetDockedPosition( Window, this, true );
            handled = true;
        }
    }
    return IntPtr.Zero;
}

当窗口停靠在边缘时.在shell中注册,它会记住从调用SHAppBarMessage / ABM_SETPOS返回的停靠矩形.当方法收到WM_WINDOWPOSCHANGED消息时,它会检查窗口是否沿边缘停靠并且没有被拖动.如果是,它将WINDOWPOS结构从非托管内存编组到托管对象中,设置位置&窗户的大小回到停靠位置&大小,并将其编组回非托管内存.然后将处理设置为true&退出.

这非常有效.防止窗户从其停靠位置反弹;返回.并且无需在窗口的Dispatcher线程上安排移动到停靠位置.

标签:c,window,wpf,taskbar
来源: https://codeday.me/bug/20190520/1141688.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有