我正在试用Ribbon
控制与RibbonWindow
结合使用,但是即使在微不足道的实验中也是如此。
System.Windows.Controls.Ribbon
引用,并删除了ribbon:
前缀(为什么示例过时?)。 我已经可以看到很多问题了:
让我们把工具栏移到底部。 现在我们看到这个:
button在工具栏之外。
最后,让我们最大化的窗口:
一半的标题消失在屏幕之外(技术上,窗口在屏幕的外侧每边8像素,但其他应用程序不会被这个混淆)。
我正在使用Windows 7,Aero,单个显示器,没有什么特别的。 我害怕在Windows 8上testing应用程序…
有什么机会解决这个问题?
在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进行编译,以强制编译器使用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,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; }