AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.8k stars 2.23k forks source link

Setting background transparency does not work on Windows Server 2016 systems #14210

Closed Naylor55 closed 9 months ago

Naylor55 commented 9 months ago

Describe the bug

Setting background transparency does not work on Windows Server 2016 systems

To Reproduce

Steps to reproduce the behavior:

  1. init a Avalonia Project
  2. setting MainWindows transparency ,I tried two ways 。 first is set Background="Transparent" , The second is use follow code

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:AvaloniaApplication1.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:views="clr-namespace:AvaloniaApplication1.Views"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaloniaApplication1.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="AvaloniaApplication1" >
        <views:MainView />
  <Window.Styles>
    <Style Selector="Window">    
      <Setter Property="Background">
        <Setter.Value>
          <SolidColorBrush Color="White" Opacity="0"></SolidColorBrush>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Styles>
</Window>
  1. build & publish
  2. Run separately on Windows11 and WindowsServer 2016

Expected behavior

Expected behavior can achieve transparency in both Windows11 and WindowsServer2016, but in reality, it is only transparent in Windows11

Screenshots

Windows11: 1

Windows Server 2016: 2

Environment

Additional context

I have attempted to modify the rendering engine to Avalonia Direct2D1 , Not solving this problem 。


  public static AppBuilder BuildAvaloniaApp()
      => AppBuilder.Configure<App>()
          .UsePlatformDetect()
          .UseDirect2D1()
          .WithInterFont()
          .LogToTrace();
maxkatz6 commented 9 months ago

Try lates nightly builds, where we have DirectComposition available on Windows backend.

Naylor55 commented 9 months ago

If the windows Server 2016 theme is set to dark, the background is black; If the windows Server 2016 theme is set to light color, the background is white. It's so interesting,Although my code has made the background transparent

timunie commented 9 months ago

RequestedThemeVariant follows system by default. So expected here if transparent fails. Does transparent works on other platforms for you btw? (edit: saw it just now)

Naylor55 commented 9 months ago

@maxkatz6 Is your suggestion for me to switch the nuget package source to avalonia-nighty ? I found a wiki and followed it, but the background still cannot be transparent on Windows Server 2016 OS

Naylor55 commented 9 months ago

After multiple attempts, I found that on Windows Server 2016, controls (eg:Border)can have background transparency, while window cannot have background transparency.

timunie commented 9 months ago

@Naylor55 what is your TransparencyLevelHint="Transparent" set to on MainWindow?

Naylor55 commented 9 months ago

@timunie I have tried many ways:


<Window
......
Background="Transparent"

>
<Window

......

        >
<Window.Styles>
    <Style Selector="Window">    
      <Setter Property="Background">
        <Setter.Value>
          <SolidColorBrush Color="White" Opacity="0"></SolidColorBrush>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Styles>

or

  <Window.Background>
    <SolidColorBrush Color="Transparent" />
  </Window.Background>

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

    }

    //根据窗体的类名或者标题名来找到窗口的句柄
    [DllImport("user32.dll", EntryPoint = "FindWindow")]
    private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

    //指定扩展窗口,以便控制窗口的透明度
    [DllImport("user32", EntryPoint = "SetWindowLong")]
    private static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong);

    //设置窗体的透明度,dwFlags指定为2时,bAlpha才能起作用
    [DllImport("user32", EntryPoint = "SetLayeredWindowAttributes")]
    private static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, int bAlpha, int dwFlags);

    [DllImport("user32", EntryPoint = "UpdateWindow")]
    private static extern uint UpdateWindow(IntPtr hwnd);

    private const uint WS_EX_LAYERED = 0x80000;
    private const int GWL_EXSTYLE = (-20); //设置为分层窗口 20 才能进行控制
    private const int LWA_ALPHA = 0x2;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="windowName"></param>
    /// <param name="windowOpacity">范围从 0(完全透明)到 255(完全不透明)</param>
    public static void changeOpacity(IPlatformHandle handle, string windowName, int windowOpacity)
    {
        uint v = SetWindowLong(handle.Handle, GWL_EXSTYLE, WS_EX_LAYERED);
        int v1 = SetLayeredWindowAttributes(handle.Handle, 0, windowOpacity, LWA_ALPHA);
        UpdateWindow(handle.Handle);
    }

    private void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {

        IPlatformHandle? platformHandle = this.TryGetPlatformHandle();
        changeOpacity(platformHandle, "", 0);

        Button b = new Button();
        b.Width = 100;
        b.Height = 100;
        b.Background = Brushes.Red;

        this.Content = b;
    }
}

These methods have all failed in Windows Server 2016 .

and then , I found a wiki ,the wiki tell me can call TopLevel.ActualTransparencyLevel to know platform was able to provide TransparencyLevel is .


        TopLevel topLevel = TopLevel.GetTopLevel(this);
        WindowTransparencyLevel actualTransparencyLevel = topLevel.ActualTransparencyLevel;
        string v = actualTransparencyLevel.ToString();

so , my current conclusion is that windows server 2016 does not support Window Transparency

timunie commented 9 months ago

I still don't see where you set TransparencyLevelHint ? This is a property that can be set by you. The defaults may differ per OS.

Naylor55 commented 9 months ago

@timunie Is it like this?


public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {
       TopLevel topLevel = TopLevel.GetTopLevel(this);
       WindowTransparencyLevel actualTransparencyLevel = topLevel.ActualTransparencyLevel;
       string v = actualTransparencyLevel.ToString();
       LogUtil.SetLogTx(v);

        List<WindowTransparencyLevel> list = new List<WindowTransparencyLevel>();
        list.Add(WindowTransparencyLevel.Transparent);
        topLevel.TransparencyLevelHint = list;
        WindowTransparencyLevel actualTransparencyLevel2 = topLevel.ActualTransparencyLevel;
        string v2 = actualTransparencyLevel.ToString();
        LogUtil.SetLogTx(v2);
    }
}

I tried setting it up through topLevel.TransparencyLevelHint =Transparent , and after setting it up, I obtained topLevel.ActualTransparencyLevel, it is still None .

timunie commented 9 months ago

no idea if that is supported that way. I only have used that property in XAML directly

Naylor55 commented 9 months ago

@timunie aha

timunie commented 9 months ago

I'm having the feeling that Windows Server does not support it correctly. So seems to be by design. See also: https://learn.microsoft.com/en-us/answers/questions/766907/window-cannot-be-made-transparent-half-transparent

Naylor55 commented 9 months ago

@timunie ok,thanks!!!