IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Průhledné okno s Aero Glass efektem v C# .NET WPF - Část 2

V minulém dílu, Průhledné okno s Aero Glass efektem v C# .NET WPF - Část 1., jsme si založili projekt a vysvětlili třídu Brushes a míchání barev. Dnes konečně vykreslíme rozmazané pozadí v naší C# .NET WPF aplikaci.

Code Behind - Krok za krokem

Zde si projdeme krok za krokem správnou implementaci volání API operačního systému. Bohužel Microsoft neuvolnil, nebo se mi alespoň nikde nepodařilo dohledat, dokumentaci, tedy vám k jednotlivým proměnným nic navíc nepovím.

1. Zavedení Interop do using deklarace

Prvně je třeba do kompilátoru zahrnout nástroje platformy Interop:

using System.Runtime.InteropServices;
using System.Windows.Interop;

2. Nastavení proměnných načítajících knihovny OS

Následující enum a struktury je třeba deklarovat v namespace našeho projektu:

internal enum AccentState
{
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_GRADIENT = 1,
    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
    ACCENT_ENABLE_BLURBEHIND = 3,
    ACCENT_INVALID_STATE = 4
}

[StructLayout(LayoutKind.Sequential)]
internal struct AccentPolicy
{
    public AccentState AccentState;
    public int AccentFlags;
    public int GradientColor;
    public int AnimationId;
}

[StructLayout(LayoutKind.Sequential)]
internal struct WindowCompositionAttributeData
{
    public WindowCompositionAttribute Attribute;
    public IntPtr Data;
    public int SizeOfData;
}

Zde se definují důležité proměnné vyžadované API operačního systému:

internal enum WindowCompositionAttribute
{
    // ...
    WCA_ACCENT_POLICY = 19
    // ...
}

Nyní si deklarujeme statické proměnné s importem systémové knihovny ve třídě našeho okna:

[DllImport("user32.dll")]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

3. Zavedení funkcí aktivujících rozmazání pozadí

Aktivaci rozmazaného pozadí našeho okna provedeme následující funkcí, kterou zavoláme z eventu Window_Loaded(), tedy potom, až se inicializují všechny ovládací prvky:

internal void EnableBlur() // Zapne rozmazání pozadí
{
    var windowHelper = new WindowInteropHelper(this);

    var accent = new AccentPolicy();
    accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;

    var accentStructSize = Marshal.SizeOf(accent);

    var accentPtr = Marshal.AllocHGlobal(accentStructSize);
    Marshal.StructureToPtr(accent, accentPtr, false);

    var data = new WindowCompositionAttributeData();
    data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
    data.SizeOfData = accentStructSize;
    data.Data = accentPtr;

    SetWindowCompositionAttribute(windowHelper.Handle, ref data);

    Marshal.FreeHGlobal(accentPtr);
}

4. Nastavení změny průhlednosti pomocí jezdce a zápisu hodnot

Pro demonstraci změny průhlednosti okna dle různé barvy, a zejména hodnoty Opacity barvy pozadí, neboli Alpha kanálu, využijeme náš <Slider>, kdy během jeho změny vyvoláme následující funkci:

private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    int a, b, c;
    a = b = c = Convert.ToInt16((sender as Slider).Value);
    string alpha = a.ToString("X2");  // převede na hexadecimální hodnotu

V první části si deklarujeme pár proměnných typu int a přiřadíme jim aktuální hodnotu našeho slideru. Vzápětí převedeme hodnotu pro alpha kanál do hexadecimální hodnoty, pomocí metody ToString("X2");. Pokračujeme dále:

a = a -(a/6);
b = b - ((b / 2));
c = c - ((c / 3));

Zde si hrajeme s RGB barvami tak, aby se měnila i jejich hodnota v poměru dle jednoduché rovnice. A posléze opět převedeme do hexadecimální hodnoty všechny kanály RGB:

string red = a.ToString("X2");  // převede na hexadecimální hodnotu
string green = b.ToString("X2");  // převede na hexadecimální hodnotu
string blue = c.ToString("X2");  // převede na hexadecimální hodnotu
/// zapis barvy ve formatu Brush
string html = "#" + alpha + red + green + blue;

Tu finální získáme tak, že jednotlivé barevné složky sloučíme do tvaru formátu HTML upraveném pro použití v Brush barvě, tedy # + ALPHA + RED + GREEN + BLUE:

    var converter = new System.Windows.Media.BrushConverter();
    this.Background = (Brush)converter.ConvertFromString(html);
    if (barva != null) barva.Text = html;
}

A nakonec vytvoříme nový BrushConverter, abychom mohli přiřazovat barvu konkrétní komponentě, v našem případě Okno.Background. Nakonec hodnotu přiřadíme prvku TextBlock, ale nejdříve si ověříme, zda byl <Slider> prvně inicializován, jinak nám program ihned spadne.

5. Doplnění funkcí formuláře

Poslední co zapracujeme, je funkce Click and drag – neboli kliknutí při držení levého tlačítka myši na formuláři, kdy jejím pohybem hýbeme i formulářem. Využijeme volání funkce MouseLeftButtonDown() formuláře:

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}

Rychlé a jednoduché, o zbytek se postará již existující funkce.

Závěr

Aplikace by měla vypadat tak jako na obrázku:

Průhledné rozmazané pozadí okna v C# .NET WPF - Zdrojákoviště C# .NET - Okenní aplikace WPF

Posuvníkem se bude měnit lineárně úroveň průhlednosti formuláře. Formuláři můžete jednoduše změnit velikost a zároveň i pozici na ploše.

Pro kontrolu celý Code Behind vypadá následovně:

using System.Runtime.InteropServices;
using System.Windows.Interop;

namespace BluredFormNETF
{
    internal enum AccentState
    {
        ACCENT_DISABLED = 0,
        ACCENT_ENABLE_GRADIENT = 1,
        ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
        ACCENT_ENABLE_BLURBEHIND = 3,
        ACCENT_INVALID_STATE = 4
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct AccentPolicy
    {
        public AccentState AccentState;
        public int AccentFlags;
        public int GradientColor;
        public int AnimationId;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WindowCompositionAttributeData
    {
        public WindowCompositionAttribute Attribute;
        public IntPtr Data;
        public int SizeOfData;
    }

    internal enum WindowCompositionAttribute
    {
        // ...
        WCA_ACCENT_POLICY = 19
        // ...
    }
    /// <summary>
    /// Interakční logika pro MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("user32.dll")]
        internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
        public MainWindow()
        {
            InitializeComponent();

        }
        internal void EnableBlur() //Zapne rozmazání pozadí
        {
            var windowHelper = new WindowInteropHelper(this);

            var accent = new AccentPolicy();
            accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;

            var accentStructSize = Marshal.SizeOf(accent);

            var accentPtr = Marshal.AllocHGlobal(accentStructSize);
            Marshal.StructureToPtr(accent, accentPtr, false);

            var data = new WindowCompositionAttributeData();
            data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
            data.SizeOfData = accentStructSize;
            data.Data = accentPtr;

            SetWindowCompositionAttribute(windowHelper.Handle, ref data);

            Marshal.FreeHGlobal(accentPtr);
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            EnableBlur();
        }

        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            int a, b, c;
            a = b = c = Convert.ToInt16((sender as Slider).Value);
            string alpha = a.ToString("X2");  //převede na hexadecimální hodnotu
            a = a -(a/3);
            b = b - ((b / 2));
            c = c - ((c / 12));
            string red = a.ToString("X2");  //převede na hexadecimální hodnotu
            string green = b.ToString("X2");  //převede na hexadecimální hodnotu
            string blue = c.ToString("X2");  //převede na hexadecimální hodnotu
            /// zapis barvy ve formatu Brush
            string html = "#" + alpha + red + green + blue;
            var converter = new System.Windows.Media.BrushConverter();
            this.Background = (Brush)converter.ConvertFromString(html);
            if (barva != null) barva.Text = html;
        }
    }
}

Doufám, že se průvodce líbil a pomohl vám s implementací průhledného okna s efektem rozmazání.


 

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 23x (299.53 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Všechny články v sekci
Zdrojákoviště C# .NET - Okenní aplikace WPF
Článek pro vás napsal Michal Kotek
Avatar
Uživatelské hodnocení:
2 hlasů
Autor se věnuje programování již od útlých let, aktuálně se věnuje výrobě Webových stránek jako fullstack, využívám Nette framework. Mám znalosti jazyků JS, PHP, SASS C# .NET, C++ pro Arduino. Jo a strašně rád střílím ;)
Aktivity