2010-09-15 12 views
5

aşağıdaki Veri Şablon bir liste kutusu uygulanan vardır:Şablonda düğmesine tıklayarak ListBoxItem nasıl seçilir?

<DataTemplate x:Key="MyTemplate" DataType="{x:Type DAL:Person}"> 
    <StackPanel Orientation="Horizontal"> 
     <Button Content="X" Command="{x:Static cmd:MyCommands.Remove}"/> 
     <TextBlock Text="{Binding Person.FullName}" /> 
    </StackPanel> 
</DataTemplate> 

komut kovuluyor butonuna tıklayın ama ListBoxItem seçili almaz zaman. Seçili öğeyi "çalıştırılmış" yöntemimde alabilmem için seçili olmaya nasıl zorlanırım?

Teşekkür

+0

Düğmeyi komut aracılığıyla geçirebilirim ve diğer taraftaki düğmeyi bulabilirim, ama bu bir kesmek gibi hissediyorum ... –

+0

Cevabımı sildim (örneğin, ListBoxItem öğesini seçen bir tetikleyici ekleyin) klavye odağı içinde olduğunda) çünkü ikinci düşüncede, çoğu durumda bunun üstesinden gelmenin en iyi yolu olmayabilir. – ASanch

+0

Aynı burada. Benim ilk çözüm CommandParameter için "Self" ve "çalıştırılan" yöntemine bağladıktan sonra LisBoxItem'i aşağıdaki gibi aldım: ListBoxItem selectedListBoxItem = ((ListBoxItem) MyListBox.ContainerFromElement ((DependencyObject) e.Parameter)); Ama bunun çok temiz olduğunu sanmıyorum ... –

cevap

8

Daha iyi bir şekilde, (hızla zaten silinecek çünkü) öğeyi seçerek gerçekten ilgilenmediğini beri CommandParameter olarak Komutanlığı'na öğenin kendisini geçmek olacaktır.

Alternatif olarak, arkasından ya da tetikleyicilere sahip döner bir şekilde devam edebilirsiniz, ancak konuyla ilgili olacağını sanmıyorum. Örneğin:

Eğer liste üzerinde ButtonBase.Click olayını ele verebilir, geride kodunuzda sonra

<ListBox ButtonBase.Click="lb_Click" 
... 

gibi Bunu yapmak:

tıklandığında bağlı öğeyi alır
private void lb_Click(object sender, RoutedEventArgs e) 
{ 
    object clicked = (e.OriginalSource as FrameworkElement).DataContext; 
    var lbi = lb.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem; 
    lbi.IsSelected = true; 
} 

, Çünkü düğmenin datacontext öğesinin öğesinden, daha sonra gerçek otomatik olarak listelenen ListBoxItem ListBox'ın ItemContainerGenerator öğesinden devralınır ve IsSelected özelliğini true olarak ayarlar. Bence bu en hızlı ve en kolay yollardan biri. Ayrıca şablonda birden fazla ButtonBase türetilmiş nesne ile çalışır. yeniden kullanılabilir Behavior olarak Tabii

ayrıca daha güzel bütün bu (az ya da çok aynı) sarabiliriz:

<ListBox xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" ...> 
    <i:Interaction.Behaviors> 
     <local:SelectItemOnButtonClick /> 
    </i:Interaction.Behaviors> 
</ListBox> 

hata ekleyin:

public class SelectItemOnButtonClick : Behavior<ListBox> 
{ 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     this.AssociatedObject.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(handler), true); 
    } 
    protected override void OnDetaching() 
    { 
     this.AssociatedObject.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(handler)); 
     base.OnDetaching(); 
    } 
    private void handler(object s, RoutedEventArgs e) 
    { 
     object clicked = (e.OriginalSource as FrameworkElement).DataContext; 
     var lbi = AssociatedObject.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem; 
     lbi.IsSelected = true; 
    } 
} 

Böyle kullanabilirsiniz En azından boş çekler gibi kod işleme tabii ki - bu, uygulamanızı bombalamak gibi basit bir şey istemez.

Sorunu anlamak için, düğme, üzerinde işlem yapılan tüm fare olayları için Handled özelliğini true olarak ayarlar (MouseDown/Click), böylece ListBoxItem tarafından dikkate alınmazlar. Ayrıca, ListBox için MouseDown olayını ekleyebilir ve üstteki ListBoxItem'e ulaşıncaya kadar görsel ağacı yukarı doğru yürütebilirsiniz, ancak bu çok daha zor ... eh merak ediyorsanız, nedenini bilmeniz için this article okuyabilirsiniz. Ayrıca, FrameworkContentElements (aynı zamanda MouseDown'a yanıt verir) ile karşılaşırsınız, böylece kod daha karmaşık hale gelir, bu durumda datatemplate içinde tıklanmış olan herhangi bir şey, olayın elleçlenip işaretlenmediğine bakılmaksızın, seçilecek ListBoxItem'i tetikler.

Heh, Ben de yalnızca üslup ve tetikleyicilerle yapmayı denedim, ancak çirkin bir şekilde hızlı oldu ve ilgimi kaybettim (ve tüm err şeylerini kaybettim). Temelde çözülebilirdi, sanırım, ama yine de çok zahmete değer olduğunu düşünmüyorum. Belki de açık bir şeyi gözden kaçırdım, bilmiyorum.

+0

Merhaba Alex, cevabınız için teşekkürler. Bu örnekte, öğeyi silmem gerekiyor, bu yüzden evet, öğeyi yalnızca komuta iletebilirim. Ama öğeyi seçmenin en kolay yolunu öğrenmek istiyorum. –

+0

İyi cevap. SL ButtonBase'de farklı tabandan gelir ve ButtonBase.ClickEvent özelliği yoktur. –

1

Temel nesnenin bir RemoveCommand özelliğini ortaya çıkarmasını sağlayın ve düğmenin Command özelliğini buna bağlayın. Bu, veri şablonunu basitleştirir; Ayrıca, uygulama mantığının belirli bir öğenin kaldırılamayacağını belirleyebileceği durumu büyük ölçüde basitleştirir.

+1

Bu noktada, temel nesnenin koleksiyon no. bu kötü görünüyor. – jr3

0

Alex, cevap için teşekkürler.Davranış ile çözümünüz harika. İlk çözüm çok iyi değil çünkü bu sadece belirli bir Düğmeye tıkladığınızda çalışacaktır. İşte keyfi kontrol formu ListBoxItem şablonu tıklama üzerinde çalışacak bir daha çözümdür:

XAML yalnızca yaklaşımdır
<ListBox.ItemContainerStyle> 
    <Style TargetType="ListBoxItem" 
      BasedOn="{StaticResource {x:Type ListBoxItem}}"> 
     <Style.Triggers> 
      <Trigger Property="IsKeyboardFocusWithin" Value="True"> 
       <Setter Property="IsSelected" Value="True"/> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 
</ListBox.ItemContainerStyle> 

. Ben de geçerli ListBoxItem stilini geçersiz kılmayacağından emin olmak için BasedOn özelliğini ayarladım.

+0

Odak, başka bir öğeye ayarlanmışsa, öğenin seçimi kaldırılmasına neden olur. Seçilmemesini istiyorsam bu yaklaşımı kullanamıyorum. – Lumo

İlgili konular