Nasıl yapılır: ContextMenuOpening Olayını İşleme

Olay ContextMenuOpening , görüntülemeden önce var olan bir bağlam menüsünü ayarlamak veya olay verilerinde özelliğini olarak ayarlayarak Handled aksi takdirde görüntülenecek menüyü engellemek için true bir uygulamada işlenebilir. Olay verilerinde olarak ayarlanmasının Handledtrue tipik nedeni, menüyü tamamen yeni ContextMenu bir nesneyle değiştirmektir; bu da bazen işlemin iptalini ve yeni bir açık başlatmayı gerektirir. Olay için işleyiciler yazarsanız, genel olarak denetimler için ContextMenuOpening bağlam menülerini açmak ve konumlandırmaktan sorumlu olan bir denetim ile hizmet arasındaki ContextMenu zamanlama sorunlarının farkında olmanız gerekir. Bu konu başlığında çeşitli bağlam menüsü açma senaryolarına yönelik kod tekniklerinden bazıları gösterilmektedir ve zamanlama sorununun devreye girdiği bir durum gösterilmektedir.

Olayı işlemek ContextMenuOpening için çeşitli senaryolar vardır:

  • Görüntüden önce menü öğelerini ayarlama.

  • Görüntüden önce menünün tamamını değiştirme.

  • Mevcut bağlam menüsünü tamamen gizleme ve bağlam menüsü görüntüleme.

Örnek

Görüntüden Önce Menü Öğelerini Ayarlama

Mevcut menü öğelerini ayarlamak oldukça basittir ve büyük olasılıkla en yaygın senaryodur. Uygulamanızdaki geçerli durum bilgilerine veya bağlam menüsünün istendiği nesnede özellik olarak kullanılabilen belirli durum bilgilerine yanıt olarak bağlam menüsü seçeneklerini eklemek veya çıkarmak için bunu yapabilirsiniz.

Genel teknik, sağ tıklanan belirli denetim olan olayın kaynağını almak ve özelliği ondan almaktır ContextMenu . Normalde, menüde hangi bağlam menüsü öğelerinin Items mevcut olduğunu görmek için koleksiyonu denetlemek ve ardından koleksiyona uygun yeni MenuItem öğeleri eklemek veya koleksiyondan kaldırmak istersiniz.

void AddItemToCM(object sender, ContextMenuEventArgs e)
{
    //check if Item4 is already there, this will probably run more than once
    FrameworkElement fe = e.Source as FrameworkElement;
    ContextMenu cm = fe.ContextMenu;
    foreach (MenuItem mi in cm.Items)
    {
        if ((String)mi.Header == "Item4") return;
    }
    MenuItem mi4 = new MenuItem();
    mi4.Header = "Item4";
    fe.ContextMenu.Items.Add(mi4);
}

Tüm Menüyü Görüntülemeden Önce Değiştirme

Alternatif bir senaryo ise bağlam menüsünün tamamını değiştirmek istemenizdir. Elbette, var olan bir bağlam menüsünün her öğesini kaldırmak ve sıfır öğesinden başlayarak yenilerini eklemek için önceki kodun bir çeşitlemesi de kullanabilirsiniz. Ancak bağlam menüsündeki tüm öğeleri değiştirmek için daha sezgisel bir yaklaşım, yeni ContextMenubir oluşturmak, öğeleriyle doldurmak ve ardından denetimin özelliğini yeni ContextMenuolarak ayarlamaktırFrameworkElement.ContextMenu.

Aşağıda, bir öğesini değiştirmek için basit işleyici kodu yer alır ContextMenu. Kod, örnek işleyicilerden birden fazlası tarafından çağrıldığından ayrılmış bir özel BuildMenu yönteme başvurur.

void HandlerForCMO(object sender, ContextMenuEventArgs e)
{
    FrameworkElement fe = e.Source as FrameworkElement;
    fe.ContextMenu = BuildMenu();
}
ContextMenu BuildMenu()
{
    ContextMenu theMenu = new ContextMenu();
    MenuItem mia = new MenuItem();
    mia.Header = "Item1";
    MenuItem mib = new MenuItem();
    mib.Header = "Item2";
    MenuItem mic = new MenuItem();
    mic.Header = "Item3";
    theMenu.Items.Add(mia);
    theMenu.Items.Add(mib);
    theMenu.Items.Add(mic);
    return theMenu;
}

Ancak, için ContextMenuOpeningbu işleyici stilini kullanırsanız, öğesini ayarladığınız ContextMenu nesnenin önceden var olan bir bağlam menüsü yoksa zamanlama sorununu ortaya çıkarabilirsiniz. Kullanıcı bir denetime sağ tıkladığında, ContextMenuOpening var olan ContextMenu boş veya null olsa bile oluşturulur. Ancak bu durumda, kaynak öğede ayarladığınız yeni ContextMenu öğeler görüntülenmek için çok geç ulaşır. Ayrıca, kullanıcı ikinci kez sağ tıkladığında, bu kez yeniniz ContextMenu görüntülenirse değer null değildir ve işleyici ikinci kez çalıştırıldığında işleyiciniz menüyü düzgün bir şekilde değiştirir ve görüntüler. Bu, iki olası geçici çözüm önerir:

  1. ContextMenuOpening İşleyicilerin her zaman en az bir yer tutucusu ContextMenu olan ve işleyici koduyla değiştirilmesini amaçladığınız denetimlerde çalışmasını sağlayın. Bu durumda, önceki örnekte gösterilen işleyiciyi kullanmaya devam edebilirsiniz, ancak genellikle ilk işaretlemede bir yer tutucu ContextMenu atamak istersiniz:

    <StackPanel>
      <Rectangle Fill="Yellow" Width="200" Height="100" ContextMenuOpening="HandlerForCMO">
        <Rectangle.ContextMenu>
          <ContextMenu>
            <MenuItem>Initial menu; this will be replaced ...</MenuItem>
          </ContextMenu>
        </Rectangle.ContextMenu>
      </Rectangle>
      <TextBlock>Right-click the rectangle above, context menu gets replaced</TextBlock>
    </StackPanel>
    
  2. Bazı ön mantık temelinde ilk ContextMenu değerin null olabileceğini varsayalım. Null olup olmadığını denetleyebilirsiniz ContextMenu veya işleyicinizin en az bir kez çalıştırılıp çalıştırılmadığını denetlemek için kodunuzda bir bayrak kullanabilirsiniz. öğesinin görüntülenmek üzere olduğunu ContextMenu varsaydığınız için işleyiciniz olay verilerinde olarak true ayarlanırHandled. Bağlam menüsünün ContextMenuService görüntülenmesinden sorumlu olan için, olay verilerindeki değeriHandled, true olayı tetikleyen bağlam menüsü / denetim bileşimi için görüntülemeyi iptal etme isteğini temsil eder.

Artık şüpheli olabilecek bağlam menüsünü gizlediğinize göre, sonraki adım yeni bir tane sağlamak ve ardından görüntülemektir. Yenisini ayarlamak temelde önceki işleyiciyle aynıdır: yeni ContextMenu bir oluşturur ve denetim kaynağının FrameworkElement.ContextMenu özelliğini onunla ayarlarsınız. Ek adım, ilk denemeyi gizlemeniz nedeniyle bağlam menüsünün görüntülenmesini zorlamanız gerektiğidir. Görüntülemeyi zorlamak için, özelliğini işleyici içinde Popup.IsOpen olarak true ayarlarsınız. Bunu yaparken dikkatli olun çünkü işleyicide bağlam menüsünü açmak olayı yeniden tetikler ContextMenuOpening . İşleyicinizi yeniden girdiğinizde, bu durum sonsuz özyinelemeli hale gelir. Bu nedenle, olay işleyicisi içinden ContextMenuOpening bir bağlam menüsü açarsanız her zaman bir bayrağı denetlemeniz null veya kullanmanız gerekir.

Mevcut Bağlam Menüsünü Gizleme ve Bağlam Menüsü Görüntüleme

Son senaryo, bir menüyü tamamen gizleyen bir işleyici yazmak nadirdir. Belirli bir denetimin bağlam menüsünü görüntülememesi gerekiyorsa, bunu sağlamanın, bir kullanıcı istediğinde menüyü gizlemeye kıyasla daha uygun yolları vardır. Ancak bir bağlam menüsünü engellemek ve hiçbir şey göstermemek için işleyiciyi kullanmak istiyorsanız, işleyiciniz olay verilerinde olarak ayarlanmalıdır Handledtrue . Bağlam ContextMenuService menüsünün görüntülenmesinden sorumlu olan, denetimde tetiklediği olayın olay verilerini denetler. Olay, yol boyunca herhangi bir yerde işaretlendiyse Handled , olayı başlatan bağlam menüsü açma eylemi gösterilmez.

    void HandlerForCMO2(object sender, ContextMenuEventArgs e)
    {
        if (!FlagForCustomContextMenu)
        {
            e.Handled = true; //need to suppress empty menu
            FrameworkElement fe = e.Source as FrameworkElement;
            fe.ContextMenu = BuildMenu();
            FlagForCustomContextMenu = true;
            fe.ContextMenu.IsOpen = true;
        }
    }
}

Ayrıca bkz.