WPF RibbonWindow + Ribbon = titre outside screen?
je suis en train de "151900920 de contrôle" en combinaison avec RibbonWindow
, cependant, ils ne parviennent pas même à trivial expériences.
- Créé de nouvelles Application WPF
- a changé le code en exemple de MSDN
- ajout d'une référence à
System.Windows.Controls.Ribbon
et suppression du préfixeribbon:
(pourquoi les exemples sont-ils périmés?). - a ajouté deux icônes (16x16 et 32x32).
- a exécuté l'application et a vu ce (Notepad de référence):
je peux déjà voir de nombreux problèmes:
- la frontière est minuscule. Une fenêtre normale a une grande bordure, l'application WPF Ribbon est minuscule. La hauteur du titre est également plus petite. La bordure
- est floue. Quand une fenêtre normale est focalisée, sa bordure est noire. La frontière de l'application WPF est gris (noir peut être vu dans les coins; quelque chose est attirée sur les frontières?).
- l'icône de L'Application est égarée. Elle est collée au coin supérieur gauche.
- titre de la demande égaré. Il est collé au dessus.
déplaçons la barre d'outils vers le bas. Maintenant nous voyons ceci:
Les boutons
se trouvent à l'extérieur de la barre d'outils.
Et enfin, maximisons la fenêtre:
la moitié de l'en-tête a disparu en dehors de l'écran (techniquement la fenêtre est en dehors de l'écran par 8 pixels de chaque côté, mais d'autres applications ne sont pas confondues par cela).
J'utilise Windows 7, Aero, single monitor, rien de spécial. J'ai peur de tester l'application sur Windows 8...
N'importe quelle chance de fixer cette?
6 réponses
le vrai problème
sous le capot, la classe WindowChrome
lie son ResizeBorderThickness
à SystemParameters.WindowResizeBorderThickness
qui utilise à tour de rôle L'API GetSystemMetrics
pour déterminer la taille de la bordure du système.
cependant, le comportement de cette méthode change en fonction de la version du sous-système définie dans L'en-tête PE exécutable. Si compilé seulement pour Windows Vista et plus tard (version >= 6.0), il sera retourner des bordures plus minces que si elles étaient compilées pour des systèmes d'exploitation plus anciens. plus d'informations à ce sujet dans cette réponse SO.
lors de la compilation avec .NET 4.5, Le compilateur c# place cette version à 6.0 puisque .NET 4.5 ne peut pas être utilisé sur XP. Cependant, la classe WindowChrome
semble s'appuyer sur le comportement de legacy et ne parvient donc pas à calculer correctement la taille du verre sur Windows Vista et 7.
Solutions
Use .NET 4
vous pouvez compiler avec .NET 4 pour forcer le compilateur à utiliser 4.0 comme valeur de version du sous-système. Le ruban est disponible pour WPF 4 en tant que téléchargement séparé . Notez que même avec cette solution, vous devez décocher "activer le processus D'hébergement Visual Studio" dans les propriétés du projet à des fins de débogage. Sinon, le vshost.le processus exe sera utilisé, qui est signalé par une version sous-système de 6.0.
changement la version du sous-système
Edit: Olly fourni un moyen de le faire dans les commentaires:
ajouter une propriété dans le dossier de projet
<subsystemversion>5.01</subsystemversion>
qui indique faussement que le code peut s'exécuter sous Windows XP.
ignorer le système
vous pouvez changer la propriété WindowChrome.WindowChrome
attachée sur votre fenêtre et utiliser les valeurs que vous voulez, donc complètement ignorer les valeurs du système. Tu ne devrais jamais faire ça, mais tu peux.
Remplir un bug
il existe un bug sur Connect concernant le changement de comportement de GetSystemMetrics
mais tout se résume à la version sous-système, donc c'est plutôt une fonctionnalité du point de vue de Microsoft view. Cependant, la classe WindowChrome
devrait vraiment être corrigée pour fonctionner correctement sous Vista/7, d'autant plus qu'elle est maintenant intégrée dans .NET 4.5.
Voici une autre Solution, très facile et simple. Il suffit d'ajouter une marge négative à la barre d'outils. Vous devez garder la classe D'origine Window et pas la 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">
il suffit d'ajouter cette marge au titre du ruban
<Ribbon Title="" Foreground="#333333" Margin="0,-22,0,0">
maintenant, quand vous maximisez la fenêtre, tout reste en ordre
pour quiconque lit cette question, je réponds moi-même. Oublie l'horrible contrôle du ruban et utilise autre chose. Cherchez quelques-unes des alternatives ici: Quelle est la meilleure suite de contrôle de ruban WPF? (comme toutes les bonnes questions, il est fermé).
jusqu'à présent, Fluent Ruban de Contrôle Suite semble être la meilleure option gratuite pour moi. La fonctionnalité de base ne fonctionne que (pas de problèmes avec les frontières et maximiser, la fenêtre de resising n'est pas aussi lente que l'enfer etc.). Il a des styles de bureau et les préserve si le verre est désactivé (cela signifie que vous ne verrez pas fenêtre Windows9x-ish dans le métro). Son interface (backstage, QAT) ressemble plus à Office 2010.
peut-être que dans un futur lointain, Microsoft va fixer son ruban, mais pour l'instant, chercher des alternatives.
ce n'est pas une solution, peut-être même pas un travail autour, mais plutôt un hack médiocre, que j'espère utiliser seulement pour un court laps de temps jusqu'à ce que le problème soit réglé dans le cadre.
Code est principalement copier+coller de cette question https://stackoverflow.com/a/8082816/44726
j'ai changé la position autorisée de l'écran, ce qui semble aider le problème, pas le corriger.
appel est comme ceci dans le code derrière
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;
}
}
j'ai eu le même problème avec le titre dans le RibbonWindow. Je l'ai résolu en définissant le style global du Textlock dans le RibbonTitlePanel.
<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>
voici ma solution de contournement. J'utilise l'événement SizeChanged
pour détecter l'état maximisé, après cela je crée de la marge pour la grille principale.
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;
}