Aracılığıyla paylaş


Liste öğelerindeki iç içe geçmiş kullanıcı arabirimi

İç içe kullanıcı arabirimi, bağımsız odak alabilen bir kapsayıcının içine alınmış iç içe yerleştirilebilir etkileşimli denetimleri görüntüleyen bir kullanıcı arabirimidir (UI).

Bir kullanıcıya önemli eylemleri hızlandırmaya yardımcı olan ek seçenekler sunmak için iç içe kullanıcı arabirimini kullanabilirsiniz. Ancak, ne kadar çok eylem gösterirseniz, kullanıcı arabiriminiz o kadar karmaşık hale gelir. Bu kullanıcı arabirimi düzenini kullanmayı seçtiğinizde fazladan dikkatli olmanız gerekir. Bu makalede, belirli bir kullanıcı arabiriminiz için en iyi eylem seyrini belirlemenize yardımcı olacak yönergeler sağlanır.

Önemli API'ler: ListView sınıfı, GridView sınıfı

Bu makalede, ListView ve GridView öğelerinde iç içe kullanıcı arabirimi oluşturma işlemi ele alınacağız. Bu bölüm diğer iç içe kullanıcı arabirimi durumlarından bahsetmese de, bu kavramlar aktarılabilir. Başlamadan önce, kullanıcı arabiriminizde ListView veya GridView denetimlerini kullanmaya yönelik genel yönergeler hakkında bilgi sahibi olmalısınız. Bu yönergeler Listeler ve Liste görünümü ve kılavuz görünümü makalelerinde bulunabilir.

Bu makalede, burada tanımlandığı gibi list, list öğesi ve iç içe geçmiş kullanıcı arayüzünü terimlerini kullanacağız:

  • Liste , liste görünümünde veya kılavuz görünümünde bulunan öğe koleksiyonunu ifade eder.
  • Liste öğesi , bir kullanıcının listede eylem gerçekleştirebileceği tek bir öğeye başvurur.
  • İç içe kullanıcı arabirimi , bir liste öğesi içindeki kullanıcı arabirimi öğelerine başvurur. Bu öğeler, kullanıcının liste öğesinin kendisinde eylem gerçekleştirmesinden ayrı olarak eylem gerçekleştirebilir.

Kapsamlı Kullanıcı Arayüzü'nün bölümlerini gösteren ekran görüntüsü.

NOT ListView ve GridView'un her ikisi de ListViewBase sınıfından türetilir, böylece aynı işlevlere sahip olur, ancak verileri farklı görüntüler. Bu makalede, listeler hakkında konuştuğumuzda, bilgiler hem ListView hem de GridView denetimleri için geçerlidir.

Birincil ve ikincil eylemler

Bir listeyle kullanıcı arabirimi oluştururken, kullanıcının bu liste öğelerinden hangi eylemleri gerçekleştirebileceğini göz önünde bulundurun.

  • Kullanıcı eylem gerçekleştirmek için öğeye tıklayabilir mi?
    • Genellikle, bir liste öğesine tıklamak bir eylem başlatır, ancak bu her zaman gerekli değildir.
  • Kullanıcının gerçekleştirebileceği birden fazla eylem var mı?
    • Örneğin, listedeki bir e-postaya dokunulduğunda bu e-posta açılır. Ancak, kullanıcının e-postayı önce açmadan yapmak isteyeceği e-postayı silme gibi başka eylemler de olabilir. Kullanıcının bu eyleme doğrudan listeden erişmesi yararlı olur.
  • Eylemler kullanıcıya nasıl gösterilmelidir?
    • Tüm giriş türlerini göz önünde bulundurun. İç içe yerleştirilmiş kullanıcı arabiriminin bazı biçimleri tek bir giriş yöntemiyle harika çalışır, ancak diğer yöntemlerle çalışmayabilir.

Birincil eylem, kullanıcının liste öğesine bastığında gerçekleşmesini beklediği eylemdir .

İkincil eylemler genellikle liste öğeleriyle ilişkili hızlandırıcılardır. Bu hızlandırıcılar liste yönetimine veya liste öğesiyle ilgili eylemlere yönelik olabilir.

İkincil eylemler için seçenekler

Liste kullanıcı arabirimi oluştururken, önce Windows'un desteklediği tüm giriş yöntemlerini hesaba eklediğinizden emin olmanız gerekir. Farklı giriş türleri hakkında daha fazla bilgi için bkz. Giriş astarı.

Uygulamanızın Windows'un desteklediği tüm girişleri desteklediğinden emin olduktan sonra, uygulamanızın ikincil eylemlerinin ana listede hızlandırıcı olarak kullanıma sunma konusunda yeterince önemli olup olmadığını belirlemeniz gerekir. Ne kadar çok eylem gösterirseniz kullanıcı arabiriminizin o kadar karmaşık hale geldiğini unutmayın. Ana liste kullanıcı arabiriminde ikincil eylemleri gerçekten kullanıma sunmanız mı gerekiyor yoksa bunları başka bir yere koyabiliyor musunuz?

Bu eylemlerin her zaman herhangi bir giriş tarafından erişilebilir olması gerektiğinde, ana liste kullanıcı arabiriminde ek eylemleri ortaya çıkarmanız gerekebilir.

İkincil eylemleri ana liste kullanıcı arabirimine yerleştirmenin gerekli olmadığına karar verirseniz, bunları kullanıcıya sunmanın birkaç yolu daha vardır. İkincil eylemlerin nereye yerleştirileceğine ilişkin olarak göz önünde bulundurabileceğiniz bazı seçenekler aşağıdadır.

İkincil eylemleri ayrıntı sayfasına yerleştirme

İkincil eylemleri, liste öğesine basıldığında gidilen sayfaya yerleştirin. Liste/ayrıntılar desenini kullandığınızda, ayrıntı sayfası genellikle ikincil eylemleri yerleştirmek için iyi bir yerdir.

Daha fazla bilgi için liste/ayrıntı düzenine bakın.

İkincil eylemleri bağlam menüsüne yerleştirme

İkincil eylemleri kullanıcının sağ tıklayarak veya basılı tutarak erişebileceği bir bağlam menüsüne yerleştirin. Bu, kullanıcının ayrıntı sayfasını yüklemek zorunda kalmadan e-posta silme gibi bir eylem gerçekleştirmesine izin verme avantajı sağlar. Bağlam menülerinin birincil kullanıcı arabirimi yerine hızlandırıcılar olması amaçlandığından, bu seçenekleri ayrıntı sayfasında da kullanılabilir hale getirmek iyi bir uygulamadır.

Giriş bir oyun çubuğundan veya uzaktan denetimden geldiğinde ikincil eylemleri kullanıma açmak için bağlam menüsü kullanmanızı öneririz.

Daha fazla bilgi için bkz. Bağlam menüleri ve açılır menüler.

İşaretçi girişi için iyileştirme yapmak için imlecin kullanıcı arabirimine ikincil eylemler yerleştirme

Uygulamanızın fare ve kalem gibi işaretçi girişiyle sık sık kullanılmasını bekliyorsanız ve ikincil eylemleri yalnızca bu girişler için kullanılabilir hale getirmek istiyorsanız, ikincil eylemleri yalnızca vurgulamada gösterebilirsiniz. Bu hızlandırıcı yalnızca bir işaretçi girişi kullanıldığında görünür, bu nedenle diğer giriş türlerini de desteklemek için diğer seçenekleri kullandığınızdan emin olun.

Üzerine gelindiğinde gösterilen iç içe kullanıcı arabirimi

Daha fazla bilgi için bkz. Fare etkileşimleri.

Birincil ve ikincil eylemler için kullanıcı arabirimi yerleştirme

İkincil eylemlerin ana liste kullanıcı arabiriminde kullanıma sunulmaya karar verirseniz aşağıdaki yönergeleri öneririz.

Birincil ve ikincil eylemlerle bir liste öğesi oluşturduğunuzda, birincil eylemi sola, ikincil eylemleri sağa yerleştirin. Soldan sağa okuma kültürlerinde, kullanıcılar liste öğesinin sol tarafındaki eylemleri birincil eylem olarak ilişkilendirir.

Bu örneklerde, öğenin daha yatay olarak aktığı (yüksekliğinden daha geniş) liste kullanıcı arabiriminden bahsediyoruz. Ancak, şekil olarak daha kare veya genişliklerinden daha uzun olan liste öğeleriniz olabilir. Bunlar genellikle gridde kullanılan öğelerdir. Bu öğeler için, liste dikey olarak kaydırılmıyorsa, ikincil eylemleri sağ tarafa değil, liste öğesinin altına yerleştirebilirsiniz.

Tüm girişleri göz önünde bulundurun

İç içe kullanıcı arabirimini kullanmaya karar verirken, tüm giriş türleriyle kullanıcı deneyimini de değerlendirin. Daha önce de belirtildiği gibi, iç içe geçmiş kullanıcı arabirimi bazı giriş türleri için harika çalışır. Ancak, bazıları için her zaman iyi sonuç vermez. Özellikle, klavye, denetleyici ve uzak girişler iç içe kullanıcı arabirimi öğelerine erişmekte zorlanabilir. Windows'unuzun tüm giriş türleriyle çalıştığından emin olmak için aşağıdaki yönergeleri izlediğinizden emin olun.

İç içe kullanıcı arayüzü (UI) yönetimi

Liste öğesinde birden fazla eylem iç içe geçmişse, klavye, oyun çubuğu, uzaktan denetim veya diğer işaretçisiz girişlerle gezintiyi işlemek için bu kılavuzu öneririz.

Liste öğelerinin eylem gerçekleştirdiği iç içe kullanıcı arabirimi

İç içe öğeler içeren liste kullanıcı arabiriminiz çağırmak, seçim (tek veya birden çok) veya sürükle ve bırak işlemleri gibi eylemleri destekliyorsa, iç içe kullanıcı arabiriminizde gezinmek için bu yönlendirme tekniklerini öneririz.

A, B, C ve D harfleriyle etiketlenmiş iç içe U I öğelerini gösteren ekran görüntüsü.

Gamepad

Giriş bir oyun çubuğundan geldiğinde şu kullanıcı deneyimini sağlayın:

  • A'dan, sağ yön tuşu odağı B'ye getirir.
  • B'den doğru yön tuşu odağı C'ye getirir.
  • C'den sağ yön tuşu ya işlem yapmaz ya da Liste'nin sağında odaklanabilir bir kullanıcı arabirimi öğesi varsa odağı oraya taşır.
  • C'den sol yön tuşu odağı B'ye getirir.
  • B'den, sol yön tuşu odağı A'ya getirir.
  • A'dan, sol yön tuşunun işlevi yoktur veya Liste'nin sağında odaklanabilir bir kullanıcı arabirimi öğesi varsa odağı oraya koyun.
  • A, B veya C'den aşağı yönlü tuş odağı D'ye getirir.
  • Liste Öğesi'nin solundaki UI öğesinden, sağ yön tuşu odağı A'ya getirir.
  • Sol yönlendirme tuşu, Liste Öğesi'nin sağındaki UI öğesinden A'ya odaklanır.

Klavye

Giriş bir klavyeden geldiğinde, kullanıcı bu deneyimi yaşar.

  • A'dan, sekme tuşu odağı B'ye getirir.
  • B'den, sekme tuşu odağı C'ye getirir.
  • C'den, sekme tuşu bir sonraki odaklanabilir kullanıcı arabirimi öğesini sekme sıradüzenine göre odaklar.
  • C'den shift+sekme tuşu odağı B'ye getirir.
  • B'den Shift+Tab veya sol ok tuşu odağı A'ya getirir.
  • A üzerinde, shift+tab tuşu odağı tersine sekme sırasındaki bir sonraki odaklanabilir kullanıcı arabirimi öğesine kaydırır.
  • A, B veya C tuşlarından aşağı ok tuşu odağı D'ye getirir.
  • Liste Öğesi'nin solundaki UI öğesinden sekme tuşu odağı A'ya getirir.
  • Liste Öğesi'nin sağındaki UI öğesinden shift sekme tuşu odağı C'ye getirir.

Bu kullanıcı arabirimini elde etmek için, listenizde IsItemClickEnableddeğerini true olarak ayarlayın. SelectionMode herhangi bir değer olabilir.

Bunu uygulayacak kod için bu makalenin Örnek bölümüne bakın.

Eylem gerçekleştirmeyen liste öğelerine sahip iç içe kullanıcı arabirimi

Sanallaştırma ve iyileştirilmiş kaydırma davranışı sağladığından, ancak liste öğesiyle ilişkilendirilmiş bir eylemi olmadığından liste görünümünü kullanabilirsiniz. Bu UI'ler genellikle öğeleri gruplandırmak ve küme olarak kaydırılmasını sağlamak için liste öğesini kullanır.

Bu tür bir kullanıcı arabirimi, kullanıcının üzerinde işlem gerçekleştirebileceği birçok iç içe öğeyle önceki örneklerden çok daha karmaşık olma eğilimindedir.

Kullanıcının etkileşim kurabileceği birçok iç içe öğeyi gösteren karmaşık İç İçe U I'nin ekran görüntüsü.

Bu kullanıcı arabirimini elde etmek için listenizde aşağıdaki özellikleri ayarlayın:

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

Liste öğeleri bir eylem gerçekleştirmediğinde, bir oyun yüzeyi veya klavye ile gezintiyi işlemek için bu kılavuzu öneririz.

Gamepad

Giriş bir oyun çubuğundan geldiğinde şu kullanıcı deneyimini sağlayın:

  • Bir Liste Öğesi'nden aşağı yön tuşu odağı bir sonraki Liste Öğesi'ne taşır.
  • Liste Öğesi'nde sol/sağ tuş herhangi bir işlem yapmaz veya Liste'nin sağında odaklanabilir bir kullanıcı arabirimi öğesi varsa, odağı oraya taşıyın.
  • Liste Öğesi'nde, 'A' düğmesi odağı yukarı/aşağı, sol/sağ öncelikli olarak iç içe geçmiş kullanıcı arayüzüne getirir.
  • "Nested UI'nin içindeyken, XY Odak gezinti modelini izleyin." Odak, kullanıcı 'B' düğmesine basana kadar geçerli Liste Öğesi içindeki İç İçe Kullanıcı Arabiriminde gezinebilir; bu düğmeye basıldığında ise odak tekrar Liste Öğesi'ne geri döner.

Klavye

Giriş bir klavyeden geldiğinde, kullanıcı bu deneyimi yaşar.

  • Liste Öğesi'nin içindeyken, aşağı ok tuşu odağı bir sonraki Liste Öğesi'ne taşır.
  • Liste Öğesi'nde sol/sağ tuşa basmak bir operasyon değildir.
  • Liste Elemanında, sekme tuşuna basıldığında odak iç içe yerleştirilmiş kullanıcı arabirimi öğeleri arasında bir sonraki sekme durağında olur.
  • İç içe geçmiş UI (Kullanıcı Arabirimi) öğelerinden birinde, sekme tuşuna basıldığında kullanıcı arabirimi öğelerinin içinde sekme sırasına göre dolaşılır. İç içe geçmiş kullanıcı arabirimi öğelerinin tümüne gidildikten sonra, odağı ListView'un ardından sekme sırasındaki bir sonraki kontrol öğesine taşır.
  • Shift+Tab, Tab davranışının ters yönünde çalışır.

Example

Bu örnekte liste öğelerinin bir eylem gerçekleştirdiği iç içe kullanıcı arabiriminin nasıl uygulanacağı gösterilmektedir.

<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:
                var rawPixelsPerViewPixel = DisplayInformation.GetForCurrentView().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;
    }
}