Beágyazott felhasználói felület listaelemekben

A beágyazott felhasználói felület egy felhasználói felület (UI), amely olyan beágyazott, végrehajtható vezérlőket tesz elérhetővé egy tárolóban, amely szintén képes független fókuszba helyezni.

A beágyazott felhasználói felülettel további lehetőségeket jeleníthet meg a felhasználók számára, amelyek segítenek felgyorsítani a fontos műveletek végrehajtását. Minél több műveletet tesz közzé, annál bonyolultabbá válik a felhasználói felülete. Ha ezt a felhasználói felületi mintát választja, különös figyelmet kell vállalnia. Ez a cikk útmutatást nyújt az adott felhasználói felülethez leginkább illő művelet meghatározásához.

Fontos API-k: ListView osztály, GridView osztály

Ebben a cikkben a beágyazott felhasználói felület ListView - és GridView-elemekben való létrehozását tárgyaljuk. Bár ez a szakasz nem beszél más beágyazott felhasználói felületi esetekről, ezek a fogalmak átvithetők. A kezdés előtt ismernie kell a ListView- vagy GridView-vezérlők felhasználói felületen való használatára vonatkozó általános útmutatót, amely a Listák és lista nézetben, valamint a rácsnézet-cikkekben található.

Ebben a cikkben az itt meghatározott kifejezéslistát, listaelemet és beágyazott felhasználói felületet használjuk:

  • A lista listanézetben vagy rácsnézetben található elemek gyűjteményére utal.
  • A listaelem olyan egyéni elemre utal, amelyen a felhasználó műveletet hajthat végre egy listában.
  • A beágyazott felhasználói felület egy listaelem felhasználói felületi elemeire hivatkozik, amelyeket a felhasználó a listaelemen végrehajtott műveletektől elkülönítve hajthat végre.

Képernyőkép a beágyazott U I részeiről.

MEGJEGYZÉS: A ListView és a GridView is a ListViewBase osztályból származik, így ugyanazzal a funkcióval rendelkeznek, de másként jelenítik meg az adatokat. Ebben a cikkben, amikor listákról beszélünk, az adatok a ListView és a GridView vezérlőkre is vonatkoznak.

Elsődleges és másodlagos műveletek

Ha listát tartalmazó felhasználói felületet hoz létre, fontolja meg, hogy a felhasználó milyen műveleteket hajthat végre ezekből a listaelemekből.

  • A felhasználó rákattinthat az elemre egy művelet végrehajtásához?
    • A listaelemre való kattintás általában műveletet indít el, de nem feltétlenül.
  • Egynél több műveletet is végrehajthat a felhasználó?
    • Például egy listában lévő e-mailre koppintva megnyílik az e-mail. Lehetnek azonban más műveletek is, például az e-mail törlése, amelyeket a felhasználó az első megnyitás nélkül szeretne végrehajtani. A felhasználó számára előnyös lenne, ha közvetlenül a listában érné el ezt a műveletet.
  • Hogyan jelenjenek meg a műveletek a felhasználó számára?
    • Vegye figyelembe az összes bemeneti típust. A beágyazott felhasználói felület egyes formái kiválóan működnek egy bemeneti módszerrel, de más módszerekkel nem működnek.

Az elsődleges művelet az, amire a felhasználó a listaelem lenyomásakor számít.

A másodlagos műveletek általában listaelemekhez társított gyorsítók. Ezek a gyorsítók lehetnek listakezelésre vagy a listaelemhez kapcsolódó műveletekre.

Másodlagos műveletek beállításai

A lista felhasználói felületének létrehozásakor először meg kell győződnie arról, hogy a Windows által támogatott összes bemeneti módszert figyelembe veszi. A különböző típusú bemenetekről további információt a Bemeneti alapozó című témakörben talál.

Miután meggyőződett arról, hogy az alkalmazás támogatja a Windows által támogatott összes bemenetet, el kell döntenie, hogy az alkalmazás másodlagos műveletei elég fontosak-e ahhoz, hogy a fő listában gyorsítóként jelenjenek meg. Ne feledje, hogy minél több műveletet tesz elérhetővé, annál bonyolultabbá válik a felhasználói felülete. Valóban el kell helyeznie a másodlagos műveleteket a fő lista felhasználói felületén, vagy máshová is el tudja helyezni őket?

Érdemes lehet további műveleteket is közzétennie a fő lista felhasználói felületén, ha ezeknek a műveleteknek bármikor elérhetőnek kell lenniük bármilyen bemenettel.

Ha úgy dönt, hogy nem szükséges másodlagos műveleteket elhelyezni a fő lista felhasználói felületén, több más módon is közzéteheti őket a felhasználó számára. Íme néhány lehetőség, amelyeket megfontolhat a másodlagos műveletek helyének beállításához.

Másodlagos műveletek elhelyezése a részletes lapon

Helyezze a másodlagos műveleteket arra a lapra, amellyel a listaelem a lenyomáskor navigál. A lista/részletek minta használatakor a részletes lap gyakran jó hely másodlagos műveletek elhelyezésére.

További információ: lista/részletminta.

Másodlagos műveletek elhelyezése helyi menüben

Helyezze a másodlagos műveleteket egy helyi menübe, amelyet a felhasználó a jobb gombbal kattintva vagy lenyomva tartva érhet el. Ez azzal az előnnyel jár, hogy a felhasználó végrehajthat egy műveletet, például törölhet egy e-mailt anélkül, hogy be kellene töltenie a részletes lapot. Célszerű ezeket a beállításokat a részletes lapon is elérhetővé tenni, mivel a helyi menük célja, hogy gyors elérést biztosítsanak, és ne szolgáljanak elsődleges felhasználói felületként.

Ha másodlagos műveleteket szeretne elérhetővé tenni, ha a bemenet egy játékpadról vagy távvezérlésből származik, javasoljuk, hogy használjon helyi menüt.

További információ: Helyi menük és felugró menük.

Másodlagos műveletek elhelyezése az egérmutató felhasználói felületén a mutató bemenetére való optimalizáláshoz

Ha azt szeretné, hogy az alkalmazást gyakran használják a mutató bemenetével, például az egérrel és a tollal, és csak ezekhez a bemenetekhez szeretné könnyen elérhetővé tenni a másodlagos műveleteket, akkor a másodlagos műveleteket csak az egérmutatón jelenítheti meg. Ez a gyorsító csak mutatóbemenet használatakor látható, ezért mindenképpen használja a többi beállítást más bemeneti típusok támogatásához is.

Rámutatáskor megjelenő beágyazott felhasználói felület

További információ: Egér-interakciók.

Felhasználói felület elhelyezése elsődleges és másodlagos műveletekhez

Ha úgy dönt, hogy a másodlagos műveleteket elérhetővé kell tenni a fő lista felhasználói felületén, az alábbi irányelveket javasoljuk.

Amikor elsődleges és másodlagos műveleteket tartalmazó listaelemet hoz létre, helyezze az elsődleges műveletet balra, a másodlagos műveleteket pedig jobbra. A balról jobbra olvasó kultúrákban a felhasználók elsődleges műveletként a listaelem bal oldalán lévő műveleteket társítják.

Ezekben a példákban a lista felhasználói felületéről beszélünk, ahol az elem vízszintesen halad (szélesebb, mint a magassága). Előfordulhat azonban, hogy vannak olyan listaelemek, amelyek négyzetesebbek, vagy magasabbak a szélességüknél. Ezek általában rácsban használt elemek. Ezeknél az elemeknél, ha a lista nem függőlegesen görget, a másodlagos műveleteket a listaelem aljára helyezheti, nem pedig a jobb oldalra.

Vegye figyelembe az összes bemenetet

A beágyazott felhasználói felület használata mellett döntve az összes bemeneti típus felhasználói élményét is értékelje. Ahogy korábban említettük, a beágyazott felhasználói felület nagyszerűen működik bizonyos bemeneti típusok esetében. Azonban ez néhány más esetben nem mindig működik jól. Különösen a billentyűzet, a vezérlő és a távoli bemenetek nehezen férnek hozzá a beágyazott felhasználói felület elemeihez. Az alábbi útmutatást követve győződjön meg arról, hogy a Windows minden bemeneti típussal működik.

Beágyazott felhasználói felület kezelése

Ha egynél több művelet van beágyazva a listaelembe, javasoljuk ezt az útmutatót a billentyűzettel, a játékpaddal, a távvezérléssel vagy más nem mutató bemenettel végzett navigáció kezeléséhez.

Beágyazott felhasználói felület, ahol a listaelemek műveletet hajtanak végre

Ha a beágyazott elemeket tartalmazó lista felhasználói felülete támogatja az olyan műveleteket, mint az invokálás, a kijelölés (egy vagy több) vagy az húzási műveletek, javasoljuk, hogy ezeket a nyílozási technikákat használja a beágyazott felhasználói felület elemeinek navigálásához.

Képernyőkép az A, B, C és D betűkkel ellátott beágyazott U I-elemekről.

Gamepad

Ha a bemenet egy játékpadról származik, adja meg ezt a felhasználói élményt:

  • Az A-ből a jobb iránykulcs a B-ra helyezi a hangsúlyt.
  • A B-ből a jobbra mutató gomb a C-re helyezi a fókuszt.
  • A C-ből a jobb iránykulcs vagy nem op, vagy ha van egy fókuszba helyezhető felhasználói felületi elem a Listától jobbra, helyezze oda a fókuszt.
  • A C-ből a bal oldali iránykulcs a B-ra helyezi a fókuszt.
  • A B-ből a bal oldali iránykulcs az A-ra helyezi a fókuszt.
  • Az A-ből a balra mutató iránygomb vagy nem művelet, vagy ha van egy fókuszba helyezhető UI elem a Lista jobb oldalán, oda kerül a fókusz.
  • Az A, B vagy C billentyűről lefelé irányuló iránykulcs a D-ra helyezi a hangsúlyt.
  • A felhasználói felület elemétől a Listaelemtől balra a jobb iránykulcs az A-ra helyezi a fókuszt.
  • A felhasználói felület elemétől a Listaelem jobb oldalán a bal oldali iránykulcs az A-ra helyezi a fókuszt.

Billentyűzet

Ha a bevitel billentyűzetről történik, a felhasználó a következő felhasználói élményt kapja:

  • Az A lapon a tabulátorbillentyű a B-ra helyezi a fókuszt.
  • A B-ből a tabulátorbillentyű a C-ra helyezi a fókuszt.
  • A C billentyűnél a tabulátorbillentyű a következő fókuszba helyezhető felhasználói felületi elemre helyezi a fókuszt a tabulátor sorrendjében.
  • A C billentyűről a Shift+Tab billentyű a B-ra helyezi a fókuszt.
  • A B billentyűnél a shift+tab vagy a balra nyílbillentyű az A-ra helyezi a fókuszt.
  • Az A gombnál a Shift+Tab billentyű a következő fókuszálható UI elemre helyezi a fókuszt a fordított tabulátorrendben.
  • Az A, B vagy C billentyűvel a lefelé mutató nyílbillentyű a D-ra helyezi a fókuszt.
  • A Felhasználói felület elemtől a Listaelemtől balra a Tab billentyű az A-ra helyezi a fókuszt.
  • A Felhasználói felület elemtől a Listaelem jobb oldalán a Shift Tab billentyű a C-ra helyezi a fókuszt.

A felhasználói felület eléréséhez állítsa az IsItemClickEnabled értéket igaz értékre a listában. A SelectionMode bármilyen érték lehet.

A kód implementálásához tekintse meg a cikk Példa szakaszát.

Beágyazott felhasználói felület, ahol a listaelemek nem hajtanak végre műveletet

Listanézetet azért használhat, mert virtualizálást és optimalizált görgetési viselkedést biztosít, de nincs listaelemhez társított művelete. Ezek a felhasználói felületek általában csak a listaelemet használják az elemek csoportosítására és azok készletként való görgetésére.

Az ilyen típusú felhasználói felület általában sokkal bonyolultabb, mint az előző példák, és sok beágyazott elem van, amelyeken a felhasználó műveletet végezhet.

Képernyőkép egy összetett beágyazott U I-ről, amelyen sok beágyazott elem látható, amelyekkel a felhasználó interakcióba léphet.

A felhasználói felület eléréséhez állítsa be a következő tulajdonságokat a listában:

<ListView SelectionMode="None" IsItemClickEnabled="False" >
    <ListView.ItemContainerStyle>
         <Style TargetType="ListViewItem">
             <Setter Property="IsFocusEngagementEnabled" Value="True"/>
         </Style>
    </ListView.ItemContainerStyle>
</ListView>

Ha a listaelemek nem hajtanak végre műveletet, javasoljuk ezt az útmutatót a játékpadon vagy billentyűzeten való navigálás kezeléséhez.

Gamepad

Ha a bemenet egy játékpadról származik, adja meg ezt a felhasználói élményt:

  • A Listaelem területen a lefelé irányuló iránykulcs a következő listaelemre helyezi a fókuszt.
  • A Listaelemből a bal/jobb billentyű vagy nem hajt végre műveletet, vagy ha van egy fókuszba helyezhető felhasználói felületi elem a Lista jobb oldalán, akkor oda helyezi a fókuszt.
  • A Listaelemben az "A" gomb a beágyazott UI-ra helyezi a fókuszt a felülről lefelé, balról jobbra prioritás szerint.
  • A beágyazott felhasználói felületen belül kövesse az XY Focus navigációs modelljét. A fókusz csak az aktuális listaelemben található beágyazott felhasználói felületen navigálhat, amíg a felhasználó meg nem nyomja a "B" gombot, amely visszahelyezi a fókuszt a Listaelemre.

Billentyűzet

Ha a bevitel billentyűzetről történik, a felhasználó a következő felhasználói élményt kapja:

  • A Listaelem területen a lefelé mutató nyílbillentyű a következő listaelemre helyezi a fókuszt.
  • A Listaelemben a bal/jobb billentyű lenyomása nem művelet.
  • A Listaelemről a tabulátorbillentyű lenyomásával a fókusz a következő tabulátorpontra kerül a beágyazott felhasználói felület elemei között.
  • Az egyik beágyazott felhasználói felületi elemből a Tab billentyű megnyomásával a beágyazott felhasználói elemek között lépegethet a tab sorrend szerinti sorrendben. Miután az összes beágyazott felhasználói felületi elemet bejárta, a fókusz a ListView utáni következő vezérlőre kerül a tabulátorsorrendben.
  • A Shift+Tab a tabulátor viselkedésétől eltérő irányban viselkedik.

Example

Ez a példa bemutatja, hogyan implementálhat beágyazott felhasználói felületet, ahol a listaelemek műveletet hajtanak végre.

<ListView SelectionMode="None" IsItemClickEnabled="True"
          ChoosingItemContainer="listview1_ChoosingItemContainer"/>
private void OnListViewItemKeyDown(object sender, KeyRoutedEventArgs e)
{
    // Code to handle going in/out of nested UI with gamepad and remote only.
    if (e.Handled == true)
    {
        return;
    }

    var focusedElementAsListViewItem = FocusManager.GetFocusedElement() as ListViewItem;
    if (focusedElementAsListViewItem != null)
    {
        // Focus is on the ListViewItem.
        // Go in with Right arrow.
        Control candidate = null;

        switch (e.OriginalKey)
        {
            case Windows.System.VirtualKey.GamepadDPadRight:
            case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
                // In WinUI 3 desktop apps, use interop to get DisplayInformation for the current window.
                var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(App.Window);
                var displayInfo = DisplayInformation.CreateForWindowId(
                    Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd));
                var rawPixelsPerViewPixel = displayInfo.RawPixelsPerViewPixel;
                GeneralTransform generalTransform = focusedElementAsListViewItem.TransformToVisual(null);
                Point startPoint = generalTransform.TransformPoint(new Point(0, 0));
                Rect hintRect = new Rect(startPoint.X * rawPixelsPerViewPixel, startPoint.Y * rawPixelsPerViewPixel, 1, focusedElementAsListViewItem.ActualHeight * rawPixelsPerViewPixel);
                candidate = FocusManager.FindNextFocusableElement(FocusNavigationDirection.Right, hintRect) as Control;
                break;
        }

        if (candidate != null)
        {
            candidate.Focus(FocusState.Keyboard);
            e.Handled = true;
        }
    }
    else
    {
        // Focus is inside the ListViewItem.
        FocusNavigationDirection direction = FocusNavigationDirection.None;
        switch (e.OriginalKey)
        {
            case Windows.System.VirtualKey.GamepadDPadUp:
            case Windows.System.VirtualKey.GamepadLeftThumbstickUp:
                direction = FocusNavigationDirection.Up;
                break;
            case Windows.System.VirtualKey.GamepadDPadDown:
            case Windows.System.VirtualKey.GamepadLeftThumbstickDown:
                direction = FocusNavigationDirection.Down;
                break;
            case Windows.System.VirtualKey.GamepadDPadLeft:
            case Windows.System.VirtualKey.GamepadLeftThumbstickLeft:
                direction = FocusNavigationDirection.Left;
                break;
            case Windows.System.VirtualKey.GamepadDPadRight:
            case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
                direction = FocusNavigationDirection.Right;
                break;
            default:
                break;
        }

        if (direction != FocusNavigationDirection.None)
        {
            Control candidate = FocusManager.FindNextFocusableElement(direction) as Control;
            if (candidate != null)
            {
                ListViewItem listViewItem = sender as ListViewItem;

                // If the next focusable candidate to the left is outside of ListViewItem,
                // put the focus on ListViewItem.
                if (direction == FocusNavigationDirection.Left &&
                    !listViewItem.IsAncestorOf(candidate))
                {
                    listViewItem.Focus(FocusState.Keyboard);
                }
                else
                {
                    candidate.Focus(FocusState.Keyboard);
                }
            }

            e.Handled = true;
        }
    }
}

private void listview1_ChoosingItemContainer(ListViewBase sender, ChoosingItemContainerEventArgs args)
{
    if (args.ItemContainer == null)
    {
        args.ItemContainer = new ListViewItem();
        args.ItemContainer.KeyDown += OnListViewItemKeyDown;
    }
}
// DependencyObjectExtensions.cs definition.
public static class DependencyObjectExtensions
{
    public static bool IsAncestorOf(this DependencyObject parent, DependencyObject child)
    {
        DependencyObject current = child;
        bool isAncestor = false;

        while (current != null && !isAncestor)
        {
            if (current == parent)
            {
                isAncestor = true;
            }

            current = VisualTreeHelper.GetParent(current);
        }

        return isAncestor;
    }
}