Slevový týden - Květen Office week
Pouze tento týden sleva až 80 % na e-learning týkající se MS Office
30 % bodů zdarma na online výuku díky naší Slevové akci!

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í

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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

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ženo 19x (299.53 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

 

Článek pro vás napsal Michal Kotek
Avatar
Jak se ti líbí článek?
2 hlasů
Autor se věnuje programování již od útlých let, aktuálně programuje rok v .NET framework pomocí C#.
Všechny články v sekci
Zdrojákoviště C# .NET - Okenní aplikace WPF
Aktivity (3)

 

 

Komentáře

Avatar
Michal Štěpánek:27.11.2019 11:06

Aplikace je prďácká, jen by to možná chtělo někam nenápadně umístit nějaké piditlačítko na zavření...

Odpovědět
27.11.2019 11:06
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Michal Kotek
Redaktor
Avatar
Michal Kotek:27.11.2019 11:12

Díky, no a na křížek jsem zapomněl: D

Odpovědět
27.11.2019 11:12
Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime.Teach a man to code...
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.