我正在试用Ribbon控制与RibbonWindow结合使用,但是即使在微不足道的实验中也是如此。
创build了新的WPF应用程序
将代码更改为MSDN中的示例
添加了对System.Windows.Controls.Ribbon引用,并删除了ribbon:前缀(为什么示例过时?)。
增加了两个图标(16×16和32×32)。
执行了应用程序,看到了这个(记事本供参考):
我已经可以看到很多问题了:
边界很小。 一个正常的窗口有一个大的边框,WPF Ribbon应用程序很小。 标题高度也较小。
边框模糊。 当一个正常的窗口被聚焦时,它的边界是黑色的。 WPF应用程序的边框是灰色的(黑色可以在angular落看到;有东西是在边界上绘制的)。
应用程序图标放错了位置。 它粘在左上angular。
应用程序标题错位。 它粘在顶部。
让我们把工具栏移到底部。 现在我们看到这个:
循环是否以相同的速度发生在所有系统上?
为我的应用程序创build属性处理程序,以将自定义属性添加到文件格式
System.Guid.NewGuid()总是通过Windows上的UuidCreate()实现吗?
我怎么能告诉我的应用程序窗口是前景窗口
在非.NET应用程序中引发SEHException
button在工具栏之外。
最后,让我们最大化的窗口:
一半的标题消失在屏幕之外(技术上,窗口在屏幕的外侧每边8像素,但其他应用程序不会被这个混淆)。
我正在使用Windows 7,Aero,单个显示器,没有什么特别的。 我害怕在Windows 8上testing应用程序…
有什么机会解决这个问题?
如何检查NotifyIcon是否隐藏
WTSQuerySessioninformation返回一个不同的域名
MonoDevelop 2.4.1不能在windows 7上运行,无法加载glibsharpglue-2
C#和部分工作的SendMessage?
吐司通知不能在Windows秋季创作者更新
真正的问题
在WindowChrome , WindowChrome类将其ResizeBorderThickness绑定到SystemParameters.WindowResizeBorderThickness ,后者轮流使用Win32 API GetSystemMetrics来确定系统边界大小。
但是,此方法的行为会根据可执行PE标头中设置的子系统版本而变化。 如果仅针对Windows Vista及更高版本(版本> = 6.0)进行编译,则它将返回比为旧版操作系统编译的更细的边界。 在这个答案更多的信息。
在针对.NET 4.5进行编译时,C#编译器将此版本设置为6.0,因为.NET 4.5无法在XP上使用。 但是, WindowChrome类似乎依赖于传统行为,因此无法在Windows Vista和7上正确计算玻璃大小。
解决方案
使用.NET 4
您可以使用.NET 4进行编译,以强制编译器使用4.0作为子系统版本值。 功能区可用于WPF 4作为单独的下载 。 请注意,即使使用此解决方案,也应该取消选中项目属性中的“启用Visual Studio宿主进程”以进行调试。 否则,将使用vshost.exe进程,该进程将使用子系统版本6.0进行标记。
更改子系统版本
在项目文件<subsystemversion>5.01</subsystemversion>中添加一个属性,错误地表示代码可以在Windows XP上运行。
忽略系统
您可以更改窗口上的WindowChrome.WindowChrome附加属性,并使用所需的值,从而完全忽略系统值。 你不应该这样做,但你可以。
填写一个错误
有关Connect的一个现有的错误, GetSystemMetrics行为发生了变化,但是这一切都归结为子系统版本,所以这是Microsoft的一个特点。 然而, WindowChrome类应该被固定在Vista / 7下正确工作,尤其是因为它现在已经构建在.NET 4.5中。
对于任何读这个问题的人,我都会自己回答。 忘掉可怕的捆绑带控制和使用别的东西。 在这里寻找一些替代方案: 什么是最好的WPF功能区控制套件? (就像所有的好问题一样,虽然封闭了)。
到目前为止, 流利的色带控制套件看起来像是我最好的免费选项。 基本的功能只是工作(没有边界的问题和最大化,resize窗口不像地狱等缓慢)。 它具有Office样式并在禁用玻璃的情况下保留它们(这意味着您不会在Metro中看到Windows9x-ish窗口)。 它的界面(后台,QAT)更像Office 2010。
也许在遥远的将来,微软将修复其功能区,但现在,寻找替代品。
这是另一个WorkAround,非常简单和简单的方法。 只需在工具栏上添加一个负边距即可。 您需要保留原始的Window类而不是RibbonWindow!
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Application Name" Height="350" Width="525" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged">
<Ribbon Title="" Foreground="#333333" Margin="0,-22,0">
现在,当你最大化的窗口,一切都保持正确
我在RibbonWindow中的标题有同样的问题。 我通过在RibbonTitlePanel中设置TextBlock的全局样式来解决这个问题。
<Style targettype="{x:Type TextBlock}"> <Style.Triggers> <multidatatrigger> <multidatatrigger.Conditions> <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type primitives:RibbonTitlePanel}},Path=Visibility}" Value="Visible"></Condition> <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type RibbonWindow}},Path=WindowState}" Value="Maximized"></Condition> </multidatatrigger.Conditions> <multidatatrigger.Setters> <Setter Property="VerticalAlignment" Value="Center"></Setter> </multidatatrigger.Setters> </multidatatrigger> </Style.Triggers> </Style>
这不是一个解决方案,可能甚至不是一个解决方法,而是一个很糟糕的做法,我希望只能使用很短的时间,直到问题在框架中得到解决。
代码主要是从这个问题复制+粘贴https://stackoverflow.com/a/8082816/44726
我已经改变了允许的屏幕位置,这似乎有助于解决问题,而不是解决问题。
InitializeComponent(); RibbonWindowService.FixMaximizedWindowTitle(this);
public static class RibbonWindowService { public static void FixMaximizedWindowTitle(Window window) { window.sourceInitialized += WinSourceInitialized; } [DllImport("user32")] internal static extern bool GetMonitorInfo(IntPtr hMonitor,MONITORINFO lpmi); [DllImport("User32")] internal static extern IntPtr MonitorFromWindow(IntPtr handle,int flags); private static IntPtr WindowProc(IntPtr hwnd,int msg,IntPtr wParam,IntPtr lParam,ref bool handled) { switch (msg) { case 0x0024: WmGetMinMaxInfo(hwnd,lParam); handled = true; break; } return (IntPtr)0; } private static void WmGetMinMaxInfo(IntPtr hwnd,IntPtr lParam) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam,typeof(MINMAXINFO)); // Adjust the maximized size and position to fit the work area of the correct monitor int MONITOR_DEFAULTTONEAREST = 0x00000002; IntPtr monitor = MonitorFromWindow(hwnd,MONITOR_DEFAULTTONEAREST); if (monitor != IntPtr.Zero) { MONITORINFO monitorInfo = new MONITORINFO(); GetMonitorInfo(monitor,monitorInfo); RECT rcWorkArea = monitorInfo.rcWork; RECT rcMonitorArea = monitorInfo.rcMonitor; // Offset top and left 1 pixel improves the situation rcMonitorArea.top += 1; rcMonitorArea.left += 1; mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left); mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top); mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left); mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); } Marshal.StructuretoPtr(mmi,lParam,true); } private static void WinSourceInitialized(object sender,EventArgs e) { IntPtr handle = (new WinInterop.WindowInteropHelper((Window)sender)).Handle; WinInterop.HwndSource.FromHwnd(handle).AddHook(WindowProc); } [StructLayout(LayoutKind.Sequential)] public struct MINMAXINFO { public POINT ptReserved; public POINT ptMaxSize; public POINT ptMaxPosition; public POINT ptMinTrackSize; public POINT ptMaxTrackSize; }; [StructLayout(LayoutKind.Sequential)] public struct POINT { /// <summary> /// x coordinate of point. /// </summary> public int x; /// <summary> /// y coordinate of point. /// </summary> public int y; /// <summary> /// Construct a point of coordinates (x,y). /// </summary> public POINT(int x,int y) { this.x = x; this.y = y; } } [StructLayout(LayoutKind.Sequential,Pack = 0)] public struct RECT { /// <summary> Win32 </summary> public int left; /// <summary> Win32 </summary> public int top; /// <summary> Win32 </summary> public int right; /// <summary> Win32 </summary> public int bottom; /// <summary> Win32 </summary> public static readonly RECT Empty = new RECT(); /// <summary> Win32 </summary> public int Width { get { return Math.Abs(right - left); } // Abs needed for BIDI OS } /// <summary> Win32 </summary> public int Height { get { return bottom - top; } } /// <summary> Win32 </summary> public RECT(int left,int top,int right,int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } /// <summary> Win32 </summary> public RECT(RECT rcSrc) { left = rcSrc.left; top = rcSrc.top; right = rcSrc.right; bottom = rcSrc.bottom; } /// <summary> Win32 </summary> public bool IsEmpty { get { // BUGBUG : On Bidi OS (hebrew arabic) left > right return left >= right || top >= bottom; } } /// <summary> Return a user friendly representation of this struct </summary> public override string ToString() { if (this == Empty) { return "RECT {Empty}"; } return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }"; } /// <summary> Determine if 2 RECT are equal (deep compare) </summary> public override bool Equals(object obj) { if (!(obj is Rect)) { return false; } return (this == (RECT)obj); } /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary> public override int GetHashCode() { return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode(); } /// <summary> Determine if 2 RECT are equal (deep compare)</summary> public static bool operator ==(RECT rect1,RECT rect2) { return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom); } /// <summary> Determine if 2 RECT are different(deep compare)</summary> public static bool operator !=(RECT rect1,RECT rect2) { return !(rect1 == rect2); } } [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Auto)] public class MONITORINFO { /// <summary> /// </summary> public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); /// <summary> /// </summary> public RECT rcMonitor = new RECT(); /// <summary> /// </summary> public RECT rcWork = new RECT(); /// <summary> /// </summary> public int dwFlags = 0; } }
这是我的解决方法。 我使用SizeChanged事件来检测最大化的状态,之后,我为主网格创建边缘。
private void Window_SizeChanged(object sender,SizeChangedEventArgs e) { Thickness m = GridMain.Margin; if (WindowState == WindowState.Maximized) { m.Left = 3; m.Bottom = 3; m.Left = 3; } else { m.Left = 0; m.Bottom = 0; m.Left = 0; } GridMain.Margin = m; }