Visual Studio 2012のようなアプリケーションを作成しようとしています。ウィンドウの境界線を削除するために WindowChrome を使用し、xamlの境界線の色を変更しました。
方法がわからないのは、ウィンドウの影をペイントすることです。ここで、私が言っていることのスクリーンショットを見ることができます。
ご覧のとおり、影があり、その色は境界線の色でもあります
WPFを使用して実装する方法を知っていますか?
もう4年が経ちましたが、これに再び取り組むことに興味があり、MahApps.Metroをもう一度いじっていました it 。私のModernChromeライブラリは、Visual Studio 2017のようなカスタムウィンドウを提供します。
輝く境界線に関する部分にのみ関心がある可能性が高いため、MahApps.Metro自体を使用するか、アタッチするクラスGlowWindowBehavior
の作成方法を確認する必要があります。カスタムModernWindow
クラスに境界線をグローします。 MahApps.Metroのいくつかの内部と、2つの依存関係プロパティGlowBrush
およびNonActiveGlowBrush
に大きく依存しています。
輝く境界線のみをカスタムアプリケーションに含める場合は、MahApps.Metroを参照して、_GlowWindowBehavior.cs
そして、カスタムウィンドウクラスを作成し、それに応じて参照を調整します。これはせいぜい15分です。
この質問と私の回答は非常に頻繁にアクセスされているので、私の最新の適切なソリューションが役立つことを願っています:)
Visual Studio 2012のユーザーインターフェイスをコピーするために、このようなライブラリに取り組んできました。カスタムのchromeはそれほど難しくありませんが、注意が必要なのは、実装が難しいこの輝く境界線です。ウィンドウの背景色を透明に設定し、メイングリッドのパディングを約30ピクセルにします。グリッドの周りの境界線に色を付け、色付きのシャドウエフェクトに関連付けることができますが、このアプローチではAllowsTransparency
をtrueに設定する必要があります。絶対にやりたくないこと!
私の現在のアプローチは、境界線に色付きの影の効果があり、透明であるがコンテンツがまったくないようなウィンドウを作成します。メインウィンドウの位置が常に変化する境界線を保持するウィンドウの位置を更新するだけです。そのため、最終的には、境界線がメインウィンドウの一部であるという偽のメッセージを含む2つのウィンドウを処理しています。これは、DWMライブラリがウィンドウに色付きのドロップシャドウ効果を与える方法を提供しないために必要でした。VisualStudio 2012は、私が試したように似ていると思います。
そして、この投稿をより多くの情報で拡張するために:Office 2013はそれを異なる方法で行います。ウィンドウの周囲の境界線は1ピクセルの太さで色付けされていますが、シャドウはDWMによって this one のようなコードで描かれています。青/紫/緑の境界線と通常の境界線なしで生活できる場合、これが私が選択するアプローチです! AllowsTransparency
をtrueに設定しないでください。そうしないと失われます。
そして、これは私のウィンドウのスクリーンショットであり、奇妙な色でそれがどのように見えるかを強調しています:
ここに開始方法のヒントがあります
私のコードは非常に長いので、基本的なことだけをお見せできるようになり、少なくとも何らかの形で開始できるはずです。まず最初に、何らかの方法で(手動またはMahApps.Metro
昨日試したパッケージ-ソースコードにいくつか修正を加えて、これは本当に良い(1))そして現在、輝く影の境界線の実装に取り組んでいます。これを今後GlowWindow
と呼びます。最も簡単な方法は、次のXAMLコードでウィンドウを作成することです
<Window x:Class="MetroUI.Views.GlowWindow"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
x:Name="GlowWindow"
Title="" Width="300" Height="100" WindowStartupLocation="Manual"
AllowsTransparency="True" Background="Transparent" WindowStyle="None"
ShowInTaskbar="False" Foreground="#007acc" MaxWidth="5000" MaxHeight="5000">
<Border x:Name="OuterGlow" Margin="10" Background="Transparent"
BorderBrush="{Binding Foreground, ElementName=GlowWindow}"
BorderThickness="5">
<Border.Effect>
<BlurEffect KernelType="Gaussian" Radius="15" RenderingBias="Quality" />
</Border.Effect>
</Border>
</Window>
結果のウィンドウは、次の図のようになります。
次の手順は非常に困難です。メインウィンドウが表示されたら、GlowWindowをメインウィンドウの背後に表示し、メインウィンドウを移動またはサイズ変更するときにGlowWindowの位置を更新する必要があります。 ANDが発生する可能性のある視覚的なグリッチを防ぐために私が提案するのは、ウィンドウの位置またはサイズの変更のたびにGlowWindowを非表示にすることです。このようなアクションが終了したら、もう一度表示します。
私はさまざまな状況で呼び出されるいくつかのメソッドを持っています(それはたくさんあるかもしれませんが、念のために)
private void UpdateGlowWindow(bool isActivated = false) {
if(this.DisableComposite || this.IsMaximized) {
this.glowWindow.Visibility = System.Windows.Visibility.Collapsed;
return;
}
try {
this.glowWindow.Left = this.Left - 10;
this.glowWindow.Top = this.Top - 10;
this.glowWindow.Width = this.Width + 20;
this.glowWindow.Height = this.Height + 20;
this.glowWindow.Visibility = System.Windows.Visibility.Visible;
if(!isActivated)
this.glowWindow.Activate();
} catch(Exception) {
}
}
このメソッドは、メインウィンドウにアタッチしたカスタムWndProc
で主に呼び出されます。
/// <summary>
/// An application-defined function that processes messages sent to a window. The WNDPROC type
/// defines a pointer to this callback function.
/// </summary>
/// <param name="hwnd">A handle to the window.</param>
/// <param name="uMsg">The message.</param>
/// <param name="wParam">Additional message information. The contents of this parameter depend on
/// the value of the uMsg parameter.</param>
/// <param name="lParam">Additional message information. The contents of this parameter depend on
/// the value of the uMsg parameter.</param>
/// <param name="handled">Reference to boolean value which indicates whether a message was handled.
/// </param>
/// <returns>The return value is the result of the message processing and depends on the message sent.
/// </returns>
private IntPtr WindowProc(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr lParam, ref bool handled) {
// BEGIN UNMANAGED WIN32
switch((WinRT.Message)uMsg) {
case WinRT.Message.WM_SIZE:
switch((WinRT.Size)wParam) {
case WinRT.Size.SIZE_MAXIMIZED:
this.Left = this.Top = 0;
if(!this.IsMaximized)
this.IsMaximized = true;
this.UpdateChrome();
break;
case WinRT.Size.SIZE_RESTORED:
if(this.IsMaximized)
this.IsMaximized = false;
this.UpdateChrome();
break;
}
break;
case WinRT.Message.WM_WINDOWPOSCHANGING:
WinRT.WINDOWPOS windowPosition = (WinRT.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WinRT.WINDOWPOS));
Window handledWindow = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
if(handledWindow == null)
return IntPtr.Zero;
bool hasChangedPosition = false;
if(this.IsMaximized == true && (this.Left != 0 || this.Top != 0)) {
windowPosition.x = windowPosition.y = 0;
windowPosition.cx = (int)SystemParameters.WorkArea.Width;
windowPosition.cy = (int)SystemParameters.WorkArea.Height;
hasChangedPosition = true;
this.UpdateChrome();
this.UpdateGlowWindow();
}
if(!hasChangedPosition)
return IntPtr.Zero;
Marshal.StructureToPtr(windowPosition, lParam, true);
handled = true;
break;
}
return IntPtr.Zero;
// END UNMANAGED WIN32
}
ただし、まだ問題が残っています。メインウィンドウのサイズを変更すると、GlowWindowはそのサイズでウィンドウ全体をカバーできなくなります。メインウィンドウのサイズを画面のMaxWidth程度に変更すると、GlowWindowのwidtは10のマージンを追加したのと同じ値+ 20になります。したがって、右端はメインウィンドウの右端の直前で中断され、見苦しくなります。これを防ぐために、フックを使用してGlowWindowをツールウィンドウにしました。
this.Loaded += delegate {
WindowInteropHelper wndHelper = new WindowInteropHelper(this);
int exStyle = (int)WinRT.GetWindowLong(wndHelper.Handle, (int)WinRT.GetWindowLongFields.GWL_EXSTYLE);
exStyle |= (int)WinRT.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
WinRT.SetWindowLong(wndHelper.Handle, (int)WinRT.GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
};
それでも、いくつかの問題が発生します。マウスをGlowWindowの上に置いて左クリックすると、GlowWindowがアクティブになり、フォーカスを取得します。つまり、次のようなメインウィンドウに重なります。
それを防ぐには、境界線のActivated
イベントをキャッチして、メインウィンドウを前面に表示します。
これをどのように行うべきですか?
私はこれを試さないことをお勧めします-私が望んでいたものを達成するのに約1ヶ月かかりましたが、Office 2013のようなアプローチに行くためにいくつかの問題があります-色付きの境界線とDWM API呼び出しによる通常の影-他には何もありませんが、それでも見栄えは良いです。
(1) ウィンドウ8で無効になっているウィンドウの周囲の境界線を有効にするために、いくつかのファイルを編集しました。さらに、タイトルバーのPadding
を操作して、その場所にスクイーズされているように見えないようにし、最後にVisual Studioのタイトルのレンダリング方法を模倣するようにAll-Capsプロパティを変更しました。これまでのMahApps.Metro
は、通常のP/Invoke呼び出しでは実装できなかったAeroSnapをサポートしているため、メインウィンドウを描画するより良い方法です。
この単純なxamlコードを使用できます
<Window x:Class="VS2012.MainWindow"
xmlns=http://schemas.Microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.Microsoft.com/winfx/2006/xaml
Title="MainWindow"
Height="100" Width="200"
AllowsTransparency="True" WindowStyle="None" Background="Transparent">
<Border BorderBrush="DarkOrange" BorderThickness="1" Background="White" Margin="5">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="5" Color="DarkOrange"/>
</Border.Effect>
</Border>
</Window>
これは「メトロスタイル」(Windows 8スタイル)と呼ばれます。 this Code Projectの記事はあなたにとって興味深いものであり、あなたの役に立つと思います。
Elysium を試すことができます。これは、MITライセンスおよび含まれるApplicationBarクラスとToastNotificationクラスの下でライセンスされています。または MetroToolKit 、codeplextからも。
This はElysiumについての素晴らしいチュートリアルであり、あなたに役立つと思います。
シャドウの場合、XAMLでBitmapEffect
からBorder
にGrid
を追加するだけです:
<Grid>
<Border BorderBrush="#FF006900" BorderThickness="3" Height="157" HorizontalAlignment="Left" Margin="12,12,0,0" Name="border1" VerticalAlignment="Top" Width="479" Background="#FFCEFFE1" CornerRadius="20, 20, 20, 20">
<Border.BitmapEffect>
<DropShadowBitmapEffect Color="Black" Direction="320" ShadowDepth="10" Opacity="0.5" Softness="5" />
</Border.BitmapEffect>
<TextBlock Height="179" Name="textBlock1" Text="Hello, this is a beautiful DropShadow WPF Window Example." FontSize="40" TextWrapping="Wrap" TextAlignment="Center" Foreground="#FF245829" />
</Border>
</Grid>
私は同じ効果を得ようとしています、私のアプリは.NET 4を使用しているため、WindowChrome
を直接使用できません(したがって、 Microsoft Windows Shell ライブラリを使用して取得します同じ)。
この thread では、spy ++を使用すると、Visual StudioにVisualStudioGlowWindowと呼ばれる4つのウィンドウがあることがわかります輝く効果。 AllowsTransparency
プロパティをtrueに設定するとパフォーマンスがどのように低下するかは、すでに多くの場所で説明されています。
だから、私はVSの方法を試みましたが、結果は悪くありません(少なくとも、私にとって);メインウィンドウでぼかしや同様の効果を使用する必要はありません。いくつかのウィンドウの状態(フォーカス/表示/非表示)で少し戦わなければなりませんでした。
github に必要なものをすべて配置しました-これが役立つことを願っています。