microsoft-ui-xaml
microsoft-ui-xaml copied to clipboard
How to display ContentDialog backdrop/smoke over custom TitleBar
As in title. Current result is this. https://imgur.com/HKuIZ4E
How to dispay it over custom titlebar? Till preview 3 all was ok.
I think you can't, it seems to be a bug. Are you targeting Win11 exclusively or do you need backwards compatibility to Win10? In W11 you should switch from the old SetTitleBar() method to the new AppWindow system. Here is a snippet of my app that might help you:
public AppWindow AW { get; set; }
public bool IsCustomizationSupported { get; set; } = false;
public MainWindow()
{
InitializeComponent();
IsCustomizationSupported = AppWindowTitleBar.IsCustomizationSupported();
if (IsCustomizationSupported)
{
AW = GetAppWindowForCurrentWindow();
AW.TitleBar.ExtendsContentIntoTitleBar = true;
CustomDragRegion.Height = 22;
AW.Title = "ConTeXt IDE";
//AW.Closing += AW_Closing;
//AW.SetIcon(Path.Combine(Package.Current.InstalledLocation.Path, @"Assets/", @"SquareLogo.png"));
}
else
{
CustomDragRegion.BackgroundTransition = null;
CustomDragRegion.Background = null;
ExtendsContentIntoTitleBar = true;
CustomDragRegion.Height = 28;
SetTitleBar(CustomDragRegion);
Title = "ConTeXt IDE";
}
}
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId myWndId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(myWndId);
}
This way, at least in W11 (where IsCustomizationSupported is true) the smoke does work in the Titlebar.
@pratikone and @bpulliam is this possible today?
I'm experiencing this as well on my app using Windows App SDK V1.0 @StephenLPeters @gabbybilka With my custom title bar and showing a ContentDialog, the entire window is blocked by the ContentDialog except for the Min, Max, and Close window buttons of the title bar. This is not the expected behavior of the ContentDialog as it is expected to block the caption buttons as well (as seen in apps such as the Win 11 Notepad)
this is not possible today unfortunately because of the way custom titlebar is implemented. we could try to make it work, maybe ? marking it as a bug .
App sdk 1.1 stable. Still not fixed. I was using this style to completely hide default titlebar and make my own.
Style
But now if I use it drag region stops working.... help please.
The reason it doesn't fill the titlebar is that the shadow has a margin set on it when XAML Window has ExtendsContentIntoTitleBar
.
So as a workaround that works on all OS, pass a function to the Loaded
event on the ContentDialog
containing one of the two code blocks. One is for C++, and the other is for C#.
// For C++
auto parent = winrt::Microsoft::UI::Xaml::Media::VisualTreeHelper::GetParent(*this);
auto child = winrt::Microsoft::UI::Xaml::Media::VisualTreeHelper::GetChild(parent, 0);
auto frame = child.as<winrt::Microsoft::UI::Xaml::Shapes::Rectangle>();
frame.Margin(ThicknessHelper::FromUniformLength(0));
frame.RegisterPropertyChangedCallback(
FrameworkElement::MarginProperty(),
[](DependencyObject const& sender, DependencyProperty const& dp) {
if (dp == FrameworkElement::MarginProperty())
sender.ClearValue(dp);
}
);
// For C#
var parent = VisualTreeHelper.GetParent(this);
var child = VisualTreeHelper.GetChild(parent, 0);
var frame = (Microsoft.UI.Xaml.Shapes.Rectangle)child;
frame.Margin = new Thickness(0);
frame.RegisterPropertyChangedCallback(
MarginProperty,
(DependencyObject sender, DependencyProperty dp) =>
{
if (dp == MarginProperty)
sender.ClearValue(dp);
});
All the code does is override the margin that XAML sets, and then make sure that XAML can't change it.
var child = VisualTreeHelper.GetChild(parent, 0);
It actually has to be:
var child = VisualTreeHelper.GetChild(parent, 2);
The third element is the smokeLayerBackground
Taking advantage of the CommunityToolkit.WinUI.UI.Behaviors.BehaviorBase class
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
/// <summary>
/// Make ContentDialog's SmokeLayerBackground dsiplay over custom titleBar
/// </summary>
public class ContentDialogBehavior : CommunityToolkit.WinUI.UI.Behaviors.BehaviorBase<FrameworkElement>
{
/// <inheritdoc/>
protected override void OnAssociatedObjectLoaded()
{
DependencyObject parent = VisualTreeHelper.GetParent(AssociatedObject);
DependencyObject child = VisualTreeHelper.GetChild(parent, 2);
Rectangle smokeLayerBackground = (Rectangle)child;
smokeLayerBackground.Margin = new Thickness(0);
smokeLayerBackground.RegisterPropertyChangedCallback(FrameworkElement.MarginProperty, OnMarginChanged);
}
private static void OnMarginChanged(DependencyObject sender, DependencyProperty property)
{
if (property == FrameworkElement.MarginProperty)
{
sender.ClearValue(property);
}
}
}
just add this to your project, and add xaml in your ContentDialog like below
<ContentDialog ...>
<mxi:Interaction.Behaviors>
<shcb:ContentDialogBehavior/>
</mxi:Interaction.Behaviors>
</ContentDialog>
Works fine for me.
I just set titlebar container height to 0 when call contentdialog. I like the last solution, but how make it work if I create dialog code behind?
ContentDialog dialog = new();
...
Microsoft.Xaml.Interactivity.Interaction.SetBehaviors(dialog, new BehaviorCollection(){new ContentDialogBehavior()});
Tested, and works. Just call SetBehaviors() before you call ShowAsync() of the dialog, I'm not sure if it will work after call rhe ShowAsync().
You are my hero.
```cs var child = VisualTreeHelper.GetChild(parent, 0);
It actually has to be:
var child = VisualTreeHelper.GetChild(parent, 2);
The third element is the smokeLayerBackground
VisualTreeHelper.GetChild(parent, 2); - Catastrophic failture VisualTreeHelper.GetChild(parent, 1); - Smoke null VisualTreeHelper.GetChild(parent, 0); - Actually works but need to test
```cs var child = VisualTreeHelper.GetChild(parent, 0);
It actually has to be:
var child = VisualTreeHelper.GetChild(parent, 2);
The third element is the smokeLayerBackground
VisualTreeHelper.GetChild(parent, 2); - Catastrophic failture VisualTreeHelper.GetChild(parent, 1); - Smoke null VisualTreeHelper.GetChild(parent, 0); - Actually works but need to test
That‘s wierd.
You can set a breakpoint and inspect the parent.Children
```cs var child = VisualTreeHelper.GetChild(parent, 0);
It actually has to be:
var child = VisualTreeHelper.GetChild(parent, 2);
The third element is the smokeLayerBackground
VisualTreeHelper.GetChild(parent, 2); - Catastrophic failture VisualTreeHelper.GetChild(parent, 1); - Smoke null VisualTreeHelper.GetChild(parent, 0); - Actually works but need to test
It cound be my issue, cause my dialog is modified from a UserContol template.
Well... Just use GetChildrenCount and a for loop to test all elements
using CommunityToolkit.WinUI.UI.Behaviors;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
/// <summary>
/// Make ContentDialog's SmokeLayerBackground dsiplay over custom titleBar
/// </summary>
public class ContentDialogBehavior : BehaviorBase<FrameworkElement>
{
/// <inheritdoc/>
protected override void OnAssociatedObjectLoaded()
{
DependencyObject parent = VisualTreeHelper.GetParent(AssociatedObject);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
DependencyObject current = VisualTreeHelper.GetChild(parent, i);
if (current is Rectangle { Name: "SmokeLayerBackground" } background)
{
background.Margin = new Thickness(0);
background.RegisterPropertyChangedCallback(FrameworkElement.MarginProperty, OnMarginChanged);
break;
}
}
}
private static void OnMarginChanged(DependencyObject sender, DependencyProperty property)
{
if (property == FrameworkElement.MarginProperty)
{
sender.ClearValue(property);
}
}
}
@Petrarca181 This should totally work now.
@Lightczx I don't know if the C# version works. The C++ version works 100% of the time, so the C# should work. If it doesn't then C# does something different to C++, and I don't know why.
@Lightczx I don't know if the C# version works. The C++ version works 100% of the time, so the C# should work. If it doesn't then C# does something different to C++, and I don't know why.
My dialog isn't created by code, and it's initialized by XAML parser. I think it's the only difference.
Ran into this today as well. A modal dialog is supposed to prevent any other input, but due to this issue the main menu is still clickable:
The "fix" also does not seem to work in version 1.2.221209.1
on Windows 10. I am unable to find any "SmokeLayerBackground"
in the visual tree.
I too am still running into this. Windows App SDK 1.2.230217.4 for Windows 10.0.19041.0 on .NET 6.
Fixed using the approach mentioned above.
dialog.Loaded += OnLoaded;
void OnLoaded(object sender, RoutedEventArgs e)
{
// Set the Theme
dialog.RequestedTheme = ThemeHelper.ActualTheme;
// Fix the smoke layer margin at the title bar
DependencyObject popupRoot = VisualTreeHelper.GetParent(dialog);
Rectangle smokeLayer = (Rectangle) VisualTreeHelper.GetChild(popupRoot, 0);
smokeLayer.Margin = new Thickness(0);
smokeLayer.RegisterPropertyChangedCallback(
FrameworkElement.MarginProperty,
(ss, dp) =>
{
if (dp == FrameworkElement.MarginProperty)
{
ss.ClearValue(dp);
}
});
}
// Show dialog
ContentDialogResult result = await dialog.ShowAsync();
A note for anyone coming across this problem still. The AppWindow
titlebar APIs in the Windows App SDK itself to not have this problem. This does mean you need to use version 1.2 or newer of Windows App SDK if you need Windows 10 support. But it is unlikely to break or be problematic, unlike the current fix of looking thru the XAML tree for the smoke effect and patching it.
And as a bonus AppWindow
's version of the caption buttons match how Win32 and UWP draw them. I don't know how the XAML team messed up the caption buttons.
I too am still running into this. Windows App SDK 1.2.230217.4 for Windows 10.0.19041.0 on .NET 6.
Fixed using the approach mentioned above.
dialog.Loaded += OnLoaded; void OnLoaded(object sender, RoutedEventArgs e) { // Set the Theme dialog.RequestedTheme = ThemeHelper.ActualTheme; // Fix the smoke layer margin at the title bar DependencyObject popupRoot = VisualTreeHelper.GetParent(dialog); Rectangle smokeLayer = (Rectangle) VisualTreeHelper.GetChild(popupRoot, 0); smokeLayer.Margin = new Thickness(0); smokeLayer.RegisterPropertyChangedCallback( FrameworkElement.MarginProperty, (ss, dp) => { if (dp == FrameworkElement.MarginProperty) { ss.ClearValue(dp); } }); } // Show dialog ContentDialogResult result = await dialog.ShowAsync();
Hi, it's not related to this issue, but how do you make your "Back" arrow appear in the title bar? I know that I should change margin of the frame but how?
how do you make your "Back" arrow appear in the title bar? I know that I should change margin of the frame but how?
Hi, @Pietro228 I'm assuming you have already set ExtendContentIntoTitleBar to true, place this peice of code in any Resources where can be applied to your NavigationView
<Thickness x:Key="NavigationViewContentMargin">0,44,0,0</Thickness>
The top margin should be consisent with you visual
title bar height
it is fixed now with winappsdk 1.4 release. I overhauled the custom titlebar implementation and implemented so that content dialog works naturally with it. (no top offset)