Megosztás a következőn keresztül:


Címsor testreszabása

A Windows minden ablakhoz alapértelmezett címsort biztosít, és lehetővé teszi az alkalmazás személyiségének megfelelő testreszabását. Az alapértelmezett címsor tartalmaz néhány szabványos összetevőt és alapvető funkciót, például az ablak húzását és átméretezését.

Egy Windows alkalmazás, amely a címsort mutatja

A címsáv tervezési cikkében útmutatást talál az alkalmazás címsorának testreszabásához, a címsor elfogadható területtartalmaihoz és az ajánlott felhasználói felületi mintákhoz.

Important

Ez a cikk bemutatja, hogyan szabhatja testre a címsort a Windows App SDK használó alkalmazásokhoz WinUI 3-val vagy anélkül. Az UWP-t és a WinUI-t UWP-hez használó alkalmazások esetében lásd: Címsor testreszabása az UWP-hez.

Important

Új címsor vezérlő lett hozzáadva a Windows App SDK 1.7-ben. Ez leegyszerűsíti a címsor testreszabásának folyamatát.

Címsor összetevői

Ez a lista a szabványos címsor összetevőit ismerteti.

  • Címsor téglalap
  • Cím szövege
  • Rendszerikon
  • Rendszer menü – az alkalmazás ikonra kattintva vagy a jobb gombbal a címsorra kattintva érhető el
  • Feliratvezérlők
    • Kis méretre állít gomb
    • Nagyítás/Visszaállítás gomb
    • Bezárás gomb

Windowing

A Windows App SDK ablakozási funkciója a Win32 HWND modellen alapuló Microsoft.UI.Windowing.AppWindow osztályon keresztül érhető el. 1:1-es leképezés található az AppWindow és egy felső szintű HWND között az alkalmazásban. Az AppWindow és a hozzá kapcsolódó osztályok olyan API-kat biztosítanak, amelyek lehetővé teszik az alkalmazás felső szintű ablakainak számos aspektusának kezelését, beleértve a címsor testreszabását is. Módosíthatja a Windows által biztosított alapértelmezett címsort, hogy az a felhasználói felület többi részével is elegyedjön, vagy kibővítse az alkalmazásvászont a címsor területére, és saját címsortartalmat biztosítson.

A WinUI ablakkezelési funkciója a Microsoft.UI.Xaml.Window osztályon keresztül érhető el, amely szintén a Win32 HWND modellen alapul. A WinUI-t használó XAML-alkalmazások esetében az XAML-ablak API-k egyszerűbb módot biztosítanak a címsor testreszabására, miközben szükség esetén hozzáférhet az AppWindow API-khoz.

Az AppWindow használata

Az AppWindow API-kat bármely olyan felhasználói felületi keretrendszerrel használhatja, amelyet a Windows App SDK támogat – Win32, WPF, WinForms vagy WinUI – és csak a szükséges API-k használatával alkalmazhatja őket növekményesen.

Ha a WinUI XAML-t használja az alkalmazás felhasználói felületi keretrendszereként, akkor az Ablak és az AppWindow API-k is elérhetők. A Windows App SDK 1.4-től kezdve az XAML ablak és az AppWindow ugyanazt a AppWindowTitleBar objektumot használja a címsor testreszabásához. A Window.AppWindow tulajdonság használatával lekérhet egy AppWindow objektumot egy meglévő XAML-ablakból. Ezzel az AppWindow-objektummal hozzáférést kap a címsor testreszabási API-ira. A címsor további funkcióinak access az XAML-ablak AppWindow API-jait a következőképpen használhatja: AppWindow.TitleBar.ForegroundColor = Colors.White;.

Ha nem WinUI 1.3-at vagy újabb verziót használ, használja az interop API-kat az AppWindow lekéréséhez, és az AppWindow API-k használatával szabja testre a címsort. Az interop API-król további információt a Az alkalmazás windows – felhasználói felület keretrendszere és a HWND interop, valamint a Windowing katalógusminta című témakörben talál.

Mennyire kell testreszabni a címsort

A címsorra kétféle testreszabási szintet alkalmazhat: kisebb módosításokat alkalmazhat az alapértelmezett címsorra, vagy kiterjesztheti az alkalmazásvászont a címsor területére, és teljesen egyéni tartalmat biztosíthat.

Simple

Az egyszerű testreszabáshoz, például a címsor színének módosításához az AppWindowTitleBar objektum tulajdonságait beállíthatja a címsorelemekhez használni kívánt színek megadásához. Ebben az esetben a rendszer fenntartja a felelősséget a címsor minden egyéb aspektusáért, például az alkalmazás címének megrajzolásáért és a húzási területek definiálásáért.

Full

A másik lehetőség, hogy elrejti az alapértelmezett rendszer címsávját, és helyettesíti azt saját, egyéni tartalommal. Elhelyezhet például szöveget, keresőmezőt vagy egyéni menüt a címsor területén. Ezzel a beállítással ki kell terjesztenie egy anyag hátterét, például a Mica-t a címsor területére.

Ha a teljes testreszabást választja, a tartalom a címsor területére kerül, és saját húzási régiókat is meghatározhat. A feliratvezérlők (a rendszer bezárása, kis méret és méret gomb) továbbra is elérhetők és kezelhetők a rendszer által, de az olyan elemek, mint az alkalmazás címe, nem. Ezeket az elemeket saját maga kell létrehoznia az alkalmazás igényei szerint.

Egyszerű testreszabás

Ha csak a címsor címét, színeit vagy ikonját szeretné testre szabni, az alkalmazás ablakának címsorobjektumában beállíthatja a tulajdonságokat.

Title

Alapértelmezés szerint a címsor ablakcímként jeleníti meg az alkalmazás típusát (például "WinUI Desktop"). Frissítenie kell az ablak címét, hogy egy értelmes megjelenítési nevet mutasson az alkalmazás számára.

Az XAML-alkalmazások megjelenítendő neve a Package.appxmanifest fájlban van beállítva. Ezt az értéket lekérheti, és így állíthatja be a Title tulajdonságot.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Az ablak címének módosításához állítsa a Window.Title tulajdonságot egy egysoros szöveges értékre az itt látható módon.

<Window
    ...
    Title="App title">
    ...
</Window>
public MainWindow()
{
    InitializeComponent();
    Title = "App title";
}

Ha az appWindow API-k használatával szeretné módosítani az ablak címét, állítsa az AppWindow.Title tulajdonságot egy egysoros szöveges értékre, ahogyan az itt látható. Ez a példa bemutatja, hogyan használhatja az interop API-kat az AppWindow beszerzéséhez, amely az alkalmazáshoz szükséges, és nem használja a WinUI 1.3-at vagy újabb verziót.

using Microsoft.UI;           // Needed for WindowId.
using Microsoft.UI.Windowing; // Needed for AppWindow.
using WinRT.Interop;          // Needed for XAML/HWND interop.

private AppWindow m_AppWindow;

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = GetAppWindowForCurrentWindow();
    m_AppWindow.Title = "App title";
}

private AppWindow GetAppWindowForCurrentWindow()
{
    IntPtr hWnd = WindowNative.GetWindowHandle(this);
    WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
    return AppWindow.GetFromWindowId(wndId);
}

Colors

Az alapértelmezett címsorszínek testreszabásához vagy az alapértelmezett ablakikon módosításához az AppWindow API-kat kell használnia, vagy a címsor teljes testreszabását kell választania.

Ez a példa bemutatja, hogyan szerezheti be az AppWindowTitleBar egy példányát , és hogyan állíthatja be annak színtulajdonságait.

Important

A szín testreszabása figyelmen kívül lesz hagyva, amikor az alkalmazás Windows 10 fut.

// Assumes "this" is a XAML Window. In projects that don't use 
// WinUI 1.3 or later, use interop APIs to get the AppWindow.
AppWindow m_AppWindow = this.AppWindow;

private bool SetTitleBarColors()
{
    // Check to see if customization is supported.
    // The method returns true on Windows 10 since Windows App SDK 1.2,
    // and on all versions of Windows App SDK on Windows 11.
    if (AppWindowTitleBar.IsCustomizationSupported())
    {
        AppWindowTitleBar m_TitleBar = m_AppWindow.TitleBar;

        // Set active window colors.
        // Note: No effect when app is running on Windows 10
        // because color customization is not supported.
        m_TitleBar.ForegroundColor = Colors.White;
        m_TitleBar.BackgroundColor = Colors.Green;
        m_TitleBar.ButtonForegroundColor = Colors.White;
        m_TitleBar.ButtonBackgroundColor = Colors.SeaGreen;
        m_TitleBar.ButtonHoverForegroundColor = Colors.Gainsboro;
        m_TitleBar.ButtonHoverBackgroundColor = Colors.DarkSeaGreen;
        m_TitleBar.ButtonPressedForegroundColor = Colors.Gray;
        m_TitleBar.ButtonPressedBackgroundColor = Colors.LightGreen;

        // Set inactive window colors.
        // Note: No effect when app is running on Windows 10
        // because color customization is not supported.
        m_TitleBar.InactiveForegroundColor = Colors.Gainsboro;
        m_TitleBar.InactiveBackgroundColor = Colors.SeaGreen;
        m_TitleBar.ButtonInactiveForegroundColor = Colors.Gainsboro;
        m_TitleBar.ButtonInactiveBackgroundColor = Colors.SeaGreen;
        return true;
    }
    return false;
}

A címsorszínek beállításakor figyelembe kell venni néhány dolgot:

  • A bezárás gomb háttérszíne nincs alkalmazva a felé mutatás és lenyomott állapotára. A bezárás gomb mindig a rendszer által meghatározott színt használja ezekhez az állapotokhoz.
  • A színtulajdonság null értékre állítása visszaállítja az alapértelmezett rendszerszínt.
  • Áttetsző színek nem állíthatók be. A szín alfa csatornája figyelmen kívül lesz hagyva.

A Windows lehetővé teszi a felhasználó számára, hogy a kijelölt jelölőszínt alkalmazza a címsorra. Ha bármilyen címsorszínt beállít, javasoljuk, hogy explicit módon állítsa be az összes színt. Ez biztosítja, hogy a felhasználó által megadott színbeállítások miatt ne fordulnak elő nem kívánt színkombinációk.

Ikon és rendszermenü

Elrejtheti a rendszerikont, vagy lecserélheti egy egyéni ikonra. A rendszerikon a rendszermenüt jeleníti meg, amikor a jobb egérgombbal kattint vagy egyszer megérinti. Bezárja az ablakot, amikor duplán kattint/koppint.

A rendszerikon és a kapcsolódó viselkedések megjelenítéséhez vagy elrejtéséhez állítsa be a címsor IconShowOptions tulajdonságát .

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Egyéni ablakikon használatához hívja meg az AppWindow.SetIcon metódusok egyikét az új ikon beállításához.

  • SetIcon(String)

    A SetIcon(String) metódus jelenleg csak .ico fájlokkal működik. Az ebbe a metódusba átadott karakterlánc a .ico fájl teljes elérési útja.

    m_AppWindow.SetIcon("iconPath/iconName.ico");
    
  • SetIcon(IconId)

    Ha már rendelkezik egy fogóponttal egy ikonhoz az HICON egyik Ikon funkcióból, például a CreateIcon-ból, a GetIconIdFromIcon interop API-val lekérheti az IconId azonosítót. Ezután átadhatja a IconId a SetIcon(IconId) metódusnak az Ön ablakikonjának beállításához.

    m_AppWindow.SetIcon(iconId));
    

Teljes testreszabás

Amikor a címsor teljes testreszabására jelentkezik be, az alkalmazás ügyfélterülete ki van terjesztve, hogy lefedje a teljes ablakot, beleértve a címsor területét is. Ön a felelős a teljes ablak rajzolásáért és beviteléért, kivéve a felirat gombokat, amelyeket az ablak továbbra is biztosít.

A rendszer címsorának elrejtéséhez és a tartalom címsorterületre való kiterjesztéséhez állítsa be azt a tulajdonságot, amely az alkalmazás tartalmát kiterjeszti a címsor területére true. XAML-alkalmazásokban ez a tulajdonság az alkalmazás OnLaunched metódusában (App.xaml.cs) vagy az alkalmazás első lapján állítható be.

Tip

A Teljes testreszabási példa szakaszban tekintheti meg az összes kódot egyszerre.

Ez a példa bemutatja, hogyan állíthatja be a Window.ExtendsContentIntoTitleBar tulajdonságot .true

public MainWindow()
{
    this.InitializeComponent();

    // Hide system title bar.
    ExtendsContentIntoTitleBar = true;
}

Caution

ExtendsContentIntoTitleBar jelenik meg az XAML IntelliSense-ben Window, de ha beállítja XAML-ben, az hibát okoz. Állítsa be ezt a tulajdonságot kódban.

Ez a példa bemutatja, hogyan szerezheti be az AppWindowTitleBart , és hogyan állíthatja be az AppWindowTitleBar.ExtendsContentIntoTitleBar tulajdonságot true. Ez a példa bemutatja, hogyan használhatja az interop API-kat az AppWindow beszerzéséhez, amelyre akkor van szükség, ha az alkalmazás nem használja a WinUI 1.3-at vagy újabb verzióját.

using Microsoft.UI;           // Needed for WindowId.
using Microsoft.UI.Windowing; // Needed for AppWindow.
using WinRT.Interop;          // Needed for XAML/HWND interop.

private AppWindow m_AppWindow;

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = GetAppWindowForCurrentWindow();
    var titleBar = m_AppWindow.TitleBar;
    // Hide system title bar.
    titleBar.ExtendsContentIntoTitleBar = true;
}

private AppWindow GetAppWindowForCurrentWindow()
{
    IntPtr hWnd = WindowNative.GetWindowHandle(this);
    WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
    return AppWindow.GetFromWindowId(wndId);
}

Címsor tartalma és az alapértelmezett húzási régió

Ha az alkalmazás ki van terjesztve a címsor területére, ön határozza meg és felügyeli a címsor felhasználói felületét. Ez általában magában foglalja legalább a cím szövegének és a húzási régiónak a megadását. A címsor húzási területe határozza meg, hogy a felhasználó hová kattinthat, és húzással mozgathatja az ablakot. A rendszermenü megjelenítéséhez a felhasználó itt is a jobb gombbal kattinthat.

A címsorok elfogadható tartalmáról és az ajánlott felhasználói felületi mintákról a címsorok kialakításával kapcsolatos további információkért lásd.

Ez a példa egy interaktív tartalom nélküli egyéni címsor felhasználói felületének XAML-ét mutatja be.

<Grid x:Name="AppTitleBar"  
      Height="32">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
    </Grid.ColumnDefinitions>
    <Image x:Name="TitleBarIcon" Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           HorizontalAlignment="Left"
           Width="16" Height="16"
           Margin="8,0,0,0"/>
    <TextBlock x:Name="TitleBarTextBlock" 
               Text="App title" 
               Style="{StaticResource CaptionTextBlockStyle}"
               Grid.Column="1"
               VerticalAlignment="Center"
               Margin="28,0,0,0"/>
</Grid>

Important

A LeftPaddingColumn és RightPaddingColumn feliratgombok helyfoglalására szolgálnak. Ezeknek Width az oszlopoknak az értékei kódban vannak beállítva, amely később jelenik meg. A kódért és a magyarázatért tekintse meg a Rendszerfelirat gombokat ismertető szakaszt.

Az XAML-alkalmazások megjelenítendő neve a Package.appxmanifest fájlban van beállítva. Megkaphatja ezt az értéket, és ilyen módon használhatja az egyéni címsorában.

TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;

Ha a tartalmat a címsor területére terjeszti, a rendszer címsora el van rejtve, és létrejön egy alapértelmezett AppWindowTitleBar , amely feliratgombokat és egy húzási területet biztosít a képernyő szélességében, amely megegyezik a rendszer címsorával. Ha nem helyez interaktív tartalmat a címsorba, hagyja meg ezt az alapértelmezett húzási régiót as-is. Ha interaktív tartalmat helyez el a címsorban, meg kell adnia az interaktív régiókat, amelyeket a következő szakaszban tárgyalunk.

Caution

Egyéni húzási régiók definiálásakor nem kell az ablak tetején lenniük az alapértelmezett címsorterületen; A felhasználói felület bármely részét húzási régióként definiálhatja. A húzási régiók különböző helyeken való elhelyezése azonban megnehezítheti a felhasználók számára a felfedezésüket.

Interaktív tartalom

Az interaktív vezérlőket, például gombokat, menüket vagy keresőmezőket az alkalmazás felső részén helyezheti el, hogy azok a címsorban jelenjenek meg. Meg kell azonban adnia, hogy mely régiók interaktívak, hogy az interaktív elemek felhasználói bemenetet kapjanak, miközben továbbra is lehetővé teszik a felhasználók számára az ablak mozgatását.

A Windows app a címsorban található keresőmezővel

Ha interaktív tartalmat ad hozzá a címsor területén, az InputNonClientPointerSource osztályt kell használnia, hogy a címsor helyett olyan területeket adjon meg, ahol a bemenet átkerül az interaktív vezérlőbe. Az interaktív régiók beállításához hívja meg az InputNonClientPointerSource.SetRegionRects metódust . Ez a metódus egy olyan értéket vesz fel, Passthroughamely meghatározza a beállított régiótípust (ebben az esetben ), valamint egy téglalapokat tartalmazó tömböt, amelyek mindegyike egy régiót Passthrough határoz meg. Amikor megváltozik a címsor mérete, újra kell számítania az interaktív régiókat az új méretnek megfelelően, és fel kell hívnia SetRegionRects az új értékekkel.

Ez a példa egy egyéni címsor felhasználói felületét mutatja be keresőmezővel és PersonPicture-fiókvezérlővel. Bemutatja, hogyan számíthatja ki és állíthatja be ezeknek a vezérlőknek az interaktív téglalapjait, hogy a bemenet áthaladjon rajtuk.

Íme néhány fontos megjegyzés a kódról:

  • Állítsa a AppTitleBar Rács magasságát 48-ra az interaktív tartalmak címsáv-tervezési útmutatójának követéséhez.
  • Állítsa be a PreferredHeightOption beállítást úgy, hogy Tall a felirat gombjai a címsor magasságával megegyező magasságban legyenek.
  • A vezérlők átméretezésének és a régiók kiszámításának megkönnyítése érdekében használjon Grid több elnevezett oszlopot az elrendezéshez.
  • Használjon csillag (*) méretezést MinWidth az azt tartalmazó AutoSuggestBox oszlophoz, hogy az automatikusan átméreteződjön az ablakkal.
  • Állítsa be a MinWidth a RightDragColumn elemet úgy, hogy lefoglaljon egy kis területet, amely mindig húzható, még akkor is, ha az ablakot átméretezik.
  • Állítsa be ExtendsContentIntoTitleBar-t true-re a MainWindow konstruktorában. Ha később meghívandó kódban állítja be, előfordulhat, hogy először az alapértelmezett rendszercímsáv jelenik meg, majd rejtett lesz.
  • Az interaktív régiók kiszámítására irányuló kezdeti hívást az AppTitleBar elem betöltése után kezdeményezze. Ellenkező esetben nincs garancia arra, hogy a számításhoz használt elemek a megfelelő értékekkel rendelkeznek.
  • Az interaktív téglalap számításait csak az AppTitleBar elem méretének (AppTitleBar_SizeChanged) módosítása után frissítse. Ha az ablakeseménytől Changed függ, előfordulhatnak olyan helyzetek (például az ablak teljes méretének/méretének csökkentése), amikor az esemény az átméretezés előtt AppTitleBar következik be, és a számítások helytelen értékeket fognak használni.
  • Csak akkor állítsa be az egyéni húzási/interaktív területeket, ha már ellenőrizte ExtendsContentIntoTitleBar, hogy egyéni címsor használatban van.
<Grid x:Name="AppTitleBar"
      Height="48">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition x:Name="IconColumn" Width="Auto"/>
        <ColumnDefinition x:Name="TitleColumn" Width="Auto"/>
        <ColumnDefinition x:Name="LeftDragColumn" Width="*"/>
        <ColumnDefinition x:Name="SearchColumn" Width="4*" MinWidth="220"/>
        <ColumnDefinition x:Name="RightDragColumn" Width="*" MinWidth="48"/>
        <ColumnDefinition x:Name="AccountColumn" Width="Auto"/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
    </Grid.ColumnDefinitions>
    <Image x:Name="TitleBarIcon" 
           Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           Width="16" Height="16"
           Margin="8,0,4,0"/>
    <TextBlock x:Name="TitleBarTextBlock"
               Text="App title" 
               Style="{StaticResource CaptionTextBlockStyle}"
               Grid.Column="2"
               VerticalAlignment="Center">
    </TextBlock>
    <AutoSuggestBox x:Name="TitleBarSearchBox" 
                    Grid.Column="4" 
                    QueryIcon="Find"
                    PlaceholderText="Search"
                    VerticalAlignment="Center"
                    MaxWidth="600"/>
    <PersonPicture x:Name="PersonPic" 
                   Grid.Column="6" 
                   Height="32" Margin="0,0,16,0"/>
</Grid>

Ez a kód bemutatja, hogyan számíthatja ki és állíthatja be az AutoSuggestBox és PersonPicture vezérlőknek megfelelő interaktív régiókat.

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        // Assumes "this" is a XAML Window. In projects that don't use 
        // WinUI 1.3 or later, use interop APIs to get the AppWindow.
        m_AppWindow = this.AppWindow;
        AppTitleBar.Loaded += AppTitleBar_Loaded;
        AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
        ExtendsContentIntoTitleBar = true;
        TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;
    }

    private void AppTitleBar_Loaded(object sender, RoutedEventArgs e)
    {
        if (ExtendsContentIntoTitleBar == true)
        {
            // Set the initial interactive regions.
            SetRegionsForCustomTitleBar();
        }
    }

    private void AppTitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (ExtendsContentIntoTitleBar == true)
        {
            // Update interactive regions if the size of the window changes.
            SetRegionsForCustomTitleBar();
        }
    }

    private void SetRegionsForCustomTitleBar()
    {
        // Specify the interactive regions of the title bar.

        double scaleAdjustment = AppTitleBar.XamlRoot.RasterizationScale;

        RightPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
        LeftPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

        GeneralTransform transform = TitleBarSearchBox.TransformToVisual(null);
        Rect bounds = transform.TransformBounds(new Rect(0, 0, 
                                                         TitleBarSearchBox.ActualWidth,
                                                         TitleBarSearchBox.ActualHeight));
        Windows.Graphics.RectInt32 SearchBoxRect = GetRect(bounds, scaleAdjustment);
        
        transform = PersonPic.TransformToVisual(null);
        bounds = transform.TransformBounds(new Rect(0, 0,
                                                    PersonPic.ActualWidth,
                                                    PersonPic.ActualHeight));
        Windows.Graphics.RectInt32 PersonPicRect = GetRect(bounds, scaleAdjustment);

        var rectArray = new Windows.Graphics.RectInt32[] { SearchBoxRect, PersonPicRect };

        InputNonClientPointerSource nonClientInputSrc =
            InputNonClientPointerSource.GetForWindowId(this.AppWindow.Id);
        nonClientInputSrc.SetRegionRects(NonClientRegionKind.Passthrough, rectArray);
    }

    private Windows.Graphics.RectInt32 GetRect(Rect bounds, double scale)
    {
        return new Windows.Graphics.RectInt32(
            _X: (int)Math.Round(bounds.X * scale),
            _Y: (int)Math.Round(bounds.Y * scale),
            _Width: (int)Math.Round(bounds.Width * scale),
            _Height: (int)Math.Round(bounds.Height * scale)
        );
    }
}

Warning

AppWindow fizikai képpontokat használ a logikai koordinátákat nem használó felhasználói felületi keretrendszerekkel való kompatibilitáshoz. Ha WPF-et vagy WinUI-t használ, a RightInset, LeftInset és a régiók kalkulálásakor használt értékeket módosítani kell, ha a skála nem 100%. Ebben a példában egy scaleAdjustment értéket kapunk, amely figyelembe veszi a megjelenítési skálázási beállítást.

  • WinUI esetén a XamlRoot.RasterizationScale tulajdonság használatával kérje le a méretezési beállításokat.
  • A WPF esetében kezelheti a Window.DpiChanged eseményt a NewDpi érték lekéréséhez és a méretezési beállítás kiszámításához.

Rendszerfelirat gombjai

A rendszer fenntartja az alkalmazásablak bal felső vagy jobb felső sarkát a rendszer felirat gombjaihoz (minimalizálás, teljes méret/visszaállítás, bezárás). A rendszer megtartja a felirat gombterületének vezérlését, így garantálva, hogy a minimális funkcionalitás biztosított legyen az ablak húzásához, minimalizálásához, maximalizálásához és bezárásához. A rendszer balról jobbra író nyelveknél a jobb felső sarokba, jobbról balra író nyelveknél pedig a bal felső sarokba rajzolja meg a Bezárás gombot.

A feliratvezérlő terület alá rajzolhat tartalmakat, például az alkalmazás hátterét, de nem szabad olyan felhasználói felületet elhelyeznie, amelyet a felhasználótól elvárhat. Nem kap bemenetet, mert a feliratvezérlők bemenetét a rendszer kezeli.

Az előző példában szereplő sorok megmutatják a címsort meghatározó XAML-ben található kitöltési oszlopokat. Margók helyett padding oszlopok használata biztosítja, hogy a háttér a feliratvezérlő gombok alatt (áttetsző gombok esetén) festse a területet. A jobb és bal kitöltési oszlopok használata biztosítja, hogy a címsor megfelelően viselkedjen mind a jobbról balra, mind a balról jobbra irányuló elrendezésekben.

<Grid.ColumnDefinitions>
    <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
    <ColumnDefinition/>
    <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
</Grid.ColumnDefinitions>

A feliratvezérlő terület méreteit és pozícióját az AppWindowTitleBar osztály közli, hogy a címsor felhasználói felületének elrendezésében figyelembe tudja venni. A fenntartott régió szélességét mindkét oldalon a LeftInset vagy a RightInset tulajdonságok adják meg, magasságát pedig a Height tulajdonság adja meg.

A kitöltési oszlopok szélessége az alábbi módon van megadva a húzási régiók kiszámításakor és beállításakor.

RightPaddingColumn.Width = 
    new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
LeftPaddingColumn.Width = 
    new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

Important

Az Interaktív tartalom szakaszban fontos információkat talál arról, hogy a megjelenítési skálázás hogyan befolyásolja ezeket az értékeket.

Magas címsorok támogatása egyéni címsorokhoz

Ha interaktív tartalmat, például keresőmezőt vagy személyképet ad hozzá a címsorban, javasoljuk, hogy növelje a címsor magasságát, hogy több helyet biztosítson ezeknek az elemeknek. A magasabb címsor megkönnyíti az érintéskezelést is. Az AppWindowTitleBar.PreferredHeightOption tulajdonság lehetővé teszi, hogy a címsor magasságát az alapértelmezett normál magasságról magasabbra növelje. Ha a Tall címsor módot választja, a rendszer által átfedőként rajzolt felirat gombok az ügyfélterületen nagyobbra jelennek meg, középre igazítva a min/max/zárás ikonokkal. Ha még nem adott meg húzási régiót, a rendszer rajzol egyet, amely kiterjeszti az ablak szélességét és a beállított érték által PreferredHeightOption meghatározott magasságot.

Ez a példa bemutatja, hogyan állíthatja be a tulajdonságot PreferredHeightOption .

// A taller title bar is only supported when drawing a fully custom title bar.
if (ExtendsContentIntoTitleBar == true)
{
    m_AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
}

Caution

Az tulajdonság beállítása előtt az true tulajdonságot kell beállítani. Ha megkísérli beállítani a PreferredHeightOption-t, miközben ExtendsContentIntoTitleBarfalse, kivételt vált ki.

Szín és átlátszóság a feliratgombokban

Ha az alkalmazás tartalmát kiterjeszti a címsor területére, áttetszővé teheti a feliratgombok hátterét, hogy az alkalmazás háttere megjelenjen. A hátteret általában Színek.Átlátszóra állítja a teljes átlátszóság érdekében. A részleges átlátszóság érdekében állítsa be annak a színnek az alfa csatornát, amelybe a tulajdonságot be szeretné állítani.

Ezek a címsortulajdonságok transzparensek lehetnek:

Az összes többi színtulajdonság továbbra is figyelmen kívül hagyja az alfa csatornát. Ha ExtendsContentIntoTitleBar be van állítva false, a rendszer mindig figyelmen kívül hagyja az alfa csatornát az összes AppWindowTitleBar színtulajdonság esetében.

A gomb háttérszíne nincs alkalmazva a Bezárás gomb rámutatási és lenyomott állapotára. A bezárás gomb mindig a rendszer által meghatározott színt használja ezekhez az állapotokhoz.

Tip

A Mica egy kellemes anyag , amely segít megkülönböztetni a fókuszban lévő ablakot. Javasoljuk, hogy a Windows 11 rendszerben a hosszú élettartamú ablakok háttérként szolgáljanak. Ha a Mica-t az ablak ügyfélterületén alkalmazta, kiterjesztheti a címsor területére, és áttetszővé teheti a feliratgombokat, hogy a Mica megjelenjen rajta. További információt a Mica anyagában talál.

A címsor elhalványítása inaktív ablak esetén

Nyilvánvalóvá kell tennie, hogy az ablak aktív vagy inaktív. Legalább módosítania kell a címsor szövegének, ikonjainak és gombjainak színét.

XAML-alkalmazások esetén kezelje a Window.Activated eseményt az ablak aktiválási állapotának meghatározásához, és szükség szerint frissítse a címsor felhasználói felületét.

public MainWindow()
{
    ...
    Activated += MainWindow_Activated;
}

private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
    if (args.WindowActivationState == WindowActivationState.Deactivated)
    {
        TitleBarTextBlock.Foreground =
            (SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
    }
    else
    {
        TitleBarTextBlock.Foreground =
            (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
    }
}

Más felhasználói felületi keretrendszerek esetén kezeljen egy eseményt az ablak aktiválási állapotának meghatározásához, és szükség szerint frissítse a címsor felhasználói felületét. Az ablak állapotának meghatározása az alkalmazáshoz használt felhasználói felületi keretrendszertől függ.

A címsor alaphelyzetbe állítása

Ha az alkalmazás futtatása közben vissza szeretné állítani vagy át szeretne váltani a rendszer címsorára, meghívhatja az AppWindowTitleBar.ResetToDefault parancsot.

m_AppWindow.TitleBar.ResetToDefault();

XAML-alkalmazások esetén a címsort is alaphelyzetbe állíthatja a következő módokon:

  • Hívja meg a SetTitleBart , hogy váltson egy új címsorelemre az alkalmazás futtatása közben.
  • Az alapértelmezett SetTitleBar húzási régiók visszaállításához hívja meg a null függvényt a AppWindowTitleBar paraméterrel.
  • Hívja meg a -t a paraméterrel, és állítsa be az ExtendsContentIntoTitleBar értékét értékre, hogy visszatérjen az alapértelmezett rendszercímsávhoz.

A címsor megjelenítése és elrejtése

Ha teljes képernyős vagy kompakt átfedési módokat ad hozzá az alkalmazáshoz, előfordulhat, hogy módosítania kell a címsort, amikor az alkalmazás vált ezek között a módok között. Az XAML-ablak nem biztosít api-kat a teljes képernyős mód támogatásához; Ehhez az AppWindow API-kat használhatja.

Amikor az alkalmazás teljes képernyős módban fut, a rendszer elrejti a címsort és a feliratvezérlő gombokat. Kezelheti az AppWindow.Changed eseményt , és ellenőrizheti az esemény args DidPresenterChange tulajdonságát annak megállapításához, hogy meg kell-e jelenítenie, elrejtenie vagy módosítania a címsort egy új ablakbemutatóra válaszul.

Ez a példa bemutatja, hogyan kezelheti a Changed eseményt, hogy megjelenítse és elrejtse az AppTitleBar elemet az előző példákból. Ha az ablak kompakt átfedési módban van, a címsor alaphelyzetbe áll az alapértelmezett rendszercímsávra (vagy megadhat egy egyéni címsort, amely kompakt átfedésre van optimalizálva).

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = this.AppWindow;
    m_AppWindow.Changed += AppWindow_Changed;
}

private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
{
    if (args.DidPresenterChange)
    {
        switch (sender.Presenter.Kind)
        {
            case AppWindowPresenterKind.CompactOverlay:
                // Compact overlay - hide custom title bar
                // and use the default system title bar instead.
                AppTitleBar.Visibility = Visibility.Collapsed;
                sender.TitleBar.ResetToDefault();
                break;

            case AppWindowPresenterKind.FullScreen:
                // Full screen - hide the custom title bar
                // and the default system title bar.
                AppTitleBar.Visibility = Visibility.Collapsed;
                sender.TitleBar.ExtendsContentIntoTitleBar = true;
                break;

            case AppWindowPresenterKind.Overlapped:
                // Normal - hide the system title bar
                // and use the custom title bar instead.
                AppTitleBar.Visibility = Visibility.Visible;
                sender.TitleBar.ExtendsContentIntoTitleBar = true;
                break;

            default:
                // Use the default system title bar.
                sender.TitleBar.ResetToDefault();
                break;
        }
    }
}

Note

A teljes képernyős és kompakt átfedési módokat csak akkor lehet megadni, ha az alkalmazás támogatja. További információ: alkalmazásablakok kezelése, FullScreenPresenterés CompactOverlayPresenter.

Amit szabad és amit nem

  • Tegye nyilvánvalóvá, ha az ablak aktív vagy inaktív. Legalább módosítsa a címsor szövegének, ikonjainak és gombjainak színét.
  • Definiáljon egy húzási régiót az alkalmazásvászon felső széle mentén. A rendszercímsávok elhelyezésével való egyeztetés megkönnyíti a felhasználók számára a keresést.
  • Definiáljon olyan húzási régiót, amely megfelel az alkalmazás vásznán lévő vizualizáció címsorának (ha van ilyen).

Teljes testreszabási példa

Ez a példa a Teljes testreszabás szakaszban leírt összes kódot mutatja be.

<Window
    x:Class="WinUI3_CustomTitleBar.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid x:Name="AppTitleBar"
      Height="48">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
                <ColumnDefinition x:Name="IconColumn" Width="Auto"/>
                <ColumnDefinition x:Name="TitleColumn" Width="Auto"/>
                <ColumnDefinition x:Name="LeftDragColumn" Width="*"/>
                <ColumnDefinition x:Name="SearchColumn" Width="4*" MinWidth="220"/>
                <ColumnDefinition x:Name="RightDragColumn" Width="*" MinWidth="48"/>
                <ColumnDefinition x:Name="AccountColumn" Width="Auto"/>
                <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
            </Grid.ColumnDefinitions>
            <Image x:Name="TitleBarIcon" 
           Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           Width="16" Height="16"
           Margin="8,0,4,0"/>
            <TextBlock x:Name="TitleBarTextBlock"
                       Text="App title" 
                       Style="{StaticResource CaptionTextBlockStyle}"
                       Grid.Column="2"
                       VerticalAlignment="Center">
            </TextBlock>
            <AutoSuggestBox x:Name="TitleBarSearchBox" 
                            Grid.Column="4" 
                            QueryIcon="Find"
                            PlaceholderText="Search"
                            VerticalAlignment="Center"
                            MaxWidth="600"/>
            <PersonPicture x:Name="PersonPic" 
                           Grid.Column="6" 
                           Height="32" Margin="0,0,16,0"/>
        </Grid>

        <NavigationView Grid.Row="1"
                        IsBackButtonVisible="Collapsed"
                        IsSettingsVisible="False">
            <StackPanel>
                <TextBlock Text="Content" 
                           Style="{ThemeResource TitleTextBlockStyle}"
                           Margin="32,0,0,0"/>
                <StackPanel Grid.Row="1" VerticalAlignment="Center">
                    <Button Margin="4" x:Name="CompactoverlaytBtn"
                            Content="Enter CompactOverlay"
                            Click="SwitchPresenter"/>
                    <Button Margin="4" x:Name="FullscreenBtn" 
                            Content="Enter FullScreen"
                            Click="SwitchPresenter"/>
                    <Button Margin="4" x:Name="OverlappedBtn"
                            Content="Revert to default (Overlapped)"
                            Click="SwitchPresenter"/>
                </StackPanel>
            </StackPanel>
        </NavigationView>
    </Grid>
</Window>
using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System;
using Windows.ApplicationModel;
using Rect = Windows.Foundation.Rect;

public sealed partial class MainWindow : Window
{
    private AppWindow m_AppWindow;

    public MainWindow()
    {
        this.InitializeComponent();

        // Assumes "this" is a XAML Window. In projects that don't use 
        // WinUI 1.3 or later, use interop APIs to get the AppWindow.
        m_AppWindow = this.AppWindow;
        m_AppWindow.Changed += AppWindow_Changed;
        Activated += MainWindow_Activated;
        AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
        AppTitleBar.Loaded += AppTitleBar_Loaded;

        ExtendsContentIntoTitleBar = true;
        if (ExtendsContentIntoTitleBar == true)
        {
            m_AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
        }
        TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;
    }

    private void AppTitleBar_Loaded(object sender, RoutedEventArgs e)
        {
            if (ExtendsContentIntoTitleBar == true)
            {
                // Set the initial interactive regions.
                SetRegionsForCustomTitleBar();
            }
        }

    private void AppTitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (ExtendsContentIntoTitleBar == true)
            {
                // Update interactive regions if the size of the window changes.
                SetRegionsForCustomTitleBar();
            }
        }

    private void SetRegionsForCustomTitleBar()
    {
        // Specify the interactive regions of the title bar.

        double scaleAdjustment = AppTitleBar.XamlRoot.RasterizationScale;

        RightPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
        LeftPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

        // Get the rectangle around the AutoSuggestBox control.
        GeneralTransform transform = TitleBarSearchBox.TransformToVisual(null);
        Rect bounds = transform.TransformBounds(new Rect(0, 0,
                                                         TitleBarSearchBox.ActualWidth,
                                                         TitleBarSearchBox.ActualHeight));
        Windows.Graphics.RectInt32 SearchBoxRect = GetRect(bounds, scaleAdjustment);

        // Get the rectangle around the PersonPicture control.
        transform = PersonPic.TransformToVisual(null);
        bounds = transform.TransformBounds(new Rect(0, 0,
                                                    PersonPic.ActualWidth,
                                                    PersonPic.ActualHeight));
        Windows.Graphics.RectInt32 PersonPicRect = GetRect(bounds, scaleAdjustment);

        var rectArray = new Windows.Graphics.RectInt32[] { SearchBoxRect, PersonPicRect };

        InputNonClientPointerSource nonClientInputSrc =
            InputNonClientPointerSource.GetForWindowId(this.AppWindow.Id);
        nonClientInputSrc.SetRegionRects(NonClientRegionKind.Passthrough, rectArray);
    }

    private Windows.Graphics.RectInt32 GetRect(Rect bounds, double scale)
    {
        return new Windows.Graphics.RectInt32(
            _X: (int)Math.Round(bounds.X * scale),
            _Y: (int)Math.Round(bounds.Y * scale),
            _Width: (int)Math.Round(bounds.Width * scale),
            _Height: (int)Math.Round(bounds.Height * scale)
        );
    }

    private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
    {
        if (args.WindowActivationState == WindowActivationState.Deactivated)
        {
            TitleBarTextBlock.Foreground =
                (SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
        }
        else
        {
            TitleBarTextBlock.Foreground =
                (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
        }
    }

    private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
    {
        if (args.DidPresenterChange)
        {
            switch (sender.Presenter.Kind)
            {
                case AppWindowPresenterKind.CompactOverlay:
                    // Compact overlay - hide custom title bar
                    // and use the default system title bar instead.
                    AppTitleBar.Visibility = Visibility.Collapsed;
                    sender.TitleBar.ResetToDefault();
                    break;

                case AppWindowPresenterKind.FullScreen:
                    // Full screen - hide the custom title bar
                    // and the default system title bar.
                    AppTitleBar.Visibility = Visibility.Collapsed;
                    sender.TitleBar.ExtendsContentIntoTitleBar = true;
                    break;

                case AppWindowPresenterKind.Overlapped:
                    // Normal - hide the system title bar
                    // and use the custom title bar instead.
                    AppTitleBar.Visibility = Visibility.Visible;
                    sender.TitleBar.ExtendsContentIntoTitleBar = true;
                    break;

                default:
                    // Use the default system title bar.
                    sender.TitleBar.ResetToDefault();
                    break;
            }
        }
    }

    private void SwitchPresenter(object sender, RoutedEventArgs e)
    {
        if (AppWindow != null)
        {
            AppWindowPresenterKind newPresenterKind;
            switch ((sender as Button).Name)
            {
                case "CompactoverlaytBtn":
                    newPresenterKind = AppWindowPresenterKind.CompactOverlay;
                    break;

                case "FullscreenBtn":
                    newPresenterKind = AppWindowPresenterKind.FullScreen;
                    break;

                case "OverlappedBtn":
                    newPresenterKind = AppWindowPresenterKind.Overlapped;
                    break;

                default:
                    newPresenterKind = AppWindowPresenterKind.Default;
                    break;
            }

            // If the same presenter button was pressed as the
            // mode we're in, toggle the window back to Default.
            if (newPresenterKind == AppWindow.Presenter.Kind)
            {
                AppWindow.SetPresenter(AppWindowPresenterKind.Default);
            }
            else
            {
                // Else request a presenter of the selected kind
                // to be created and applied to the window.
                AppWindow.SetPresenter(newPresenterKind);
            }
        }
    }
}