简体   繁体   English

如何通过按其子元素将焦点设置到绑定的ListboxItem?

[英]How to set focus to a bound ListboxItem by pressing its child element?

I am developping a small WPF application which consist mostly in displaying ObservableCollection<> in others ObservableCollection<> , and so on. 我该深化发展主要由在显示一个小WPF应用程序ObservableCollection<>在别人ObservableCollection<>等等。

Here is a code example of what my application looks like: 这是我的应用程序外观的代码示例:

<Listbox Name="MainList" ItemsSource={Binding}>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>      

                <Textblock Text={Binding MainName} />
                <Button>Add item</Button>
                <Button>Delete item</Button>

                <Listbox Name="ChildList" ItemsSource="{Binding Path=ChildItem}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Textblock Text={Binding ChildName} />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </Listbox>

            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</Listbox>

And visually it pretty much looks like this: 从视觉上看,它看起来像这样:

应用实例

EDIT: 编辑:

I will re-explain what I am trying to do. 我将重新解释我要做什么。

  • Whenever I click Button A or Button B I want to Select the MainList ListBoxItem in which they are contained (ie: A Item ) 每当我单击Button AButton B我都想选择包含它们的MainList ListBoxItem (即: A Item

  • And in a second time whenever I click Button B : 第二次,每当我单击Button B

    • I want to be sure that a ListBoxItem is selected in ChildList (Second Listbox in the picture) 我想确保在ChildList选择了一个ListBoxItem (图片中的第二个Listbox)
    • And if so, I want to delete it in code-behind. 如果是这样,我想在代码隐藏中将其删除。

But my main problem is since everything is generated by my bindings I cannot get, so far, an element from my ChildList because ChildList is duplicated in any of my MainList ListBoxItem . 但是我的主要问题是,由于一切都是由绑定生成的,所以到目前为止,我ChildListChildList获得一个元素,因为ChildList在任何MainList ListBoxItem都是重复的。

If I understand well the problem is that you want first click on a button of unselected item to select the MainItem , and on next click, when MainItem is already selected, preform click action. 如果我对问题的理解很好,那就是您希望首先单击未选择项目的按钮以选择MainItem ,然后在下次单击时(已经选择MainItem时) MainItem单击操作。 Try this when button is clicked: 单击按钮时请尝试以下操作:

private ListBoxItem FindItemContainer(DependencyObject obj)
{
   while (obj != null && !(obj is ListBoxItem))
   {
       obj = VisualTreeHelper.GetParent(obj);
   }

   if (obj != null)
       return obj as ListBoxItem;
   else
       return null;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
   var lbi = FindItemContainer(sender as DependencyObject);
   if (lbi != null)
   {
       if (lbi.IsSelected)
       {
           //do click event
       }
       else
           lbi.IsSelected = true;
   }
}

Of course you can also do it more MVVM way by binding ListBoxItem.IsSelected to lets say bool MainItem.MyItemIsSelected 当然,您也可以通过将ListBoxItem.IsSelected绑定为bool MainItem.MyItemIsSelected来执行更多MVVM方法

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="IsSelected" Value="{Binding Path=MyItemIsSelected, Mode=TwoWay}"/>
    </Style>
</ListBox.ItemContainerStyle>

and Button.Command to your ICommand MainItem.DeleteCommand and then when command is executed do something like that: Button.CommandICommand MainItem.DeleteCommand ,然后在执行命令时执行以下操作:

if (MyItemIsSelected)
{
    //do command body
}
else
    MyItemIsSelected = true;

which will be better long term because you could replicate SelectedItem behaviour in ChildList object (add MyItemIsSelected and bind it to inner 'ListBoxItem.IsSelected , like discribed above) and add MySelectedItem property to ChildList : 从长远来看这会更好,因为您可以在ChildList对象中复制SelectedItem行为(添加MyItemIsSelected并将其绑定到内部的'ListBoxItem.IsSelected ,如上文所述),然后将MySelectedItem属性添加到ChildList

ChildItem MySelectedItem
{
   get
   {
      return Items.FirstOrDefault(n=>n.MyItemIsSelected);
   }
}

and your delete command would look like this: 您的删除命令将如下所示:

if (MyItemIsSelected)
{
    ChildItem selItem = ChildItems.MySelectedItem;
    if (selItem != null) ChildItems.Items.Remove(selItem);
}
else
    MyItemIsSelected = true;

if everything is data bound and lists are ObservableCollections then you can do all that in object and UI will follow. 如果所有内容都是数据绑定的,并且列表是ObservableCollections则可以在object和UI中进行所有操作。 Actually you can do only this child selection binding bit and still use first solution and in Button_Click look like this: 实际上,您只能执行此子选择绑定位,并且仍然使用第一个解决方案,并且在Button_Click如下所示:

private void Button_Click(object sender, RoutedEventArgs e)
{
   var lbi = FindItemContainer(sender as DependencyObject);
   if (lbi != null)
   {
       if (lbi.IsSelected)
       {
           MainItem mainItem = lbi.Content as MainItem;
           ChildItem selChild = mainItem.ChildItems.MySelectedItem;
           if (selChild != null) mainItem.ChildItems.Items.Remove(selChild);
       }
       else
           lbi.IsSelected = true;
   }
}

Here is simple, working example on Dropbox 这是Dropbox上的简单工作示例

You can do everything you want to do in code behind: 您可以在后面的代码中做所有想做的事情:

  • Find the item on which the Button is pressed: in the click-event, cast the sender parameter to type Button. 查找按下按钮的项目:在click事件中,将sender参数强制转换为键入Button。 Its DataContext property will contain the item you want to select. 其DataContext属性将包含您要选择的项目。
  • Select the item: set MainList.SelectedItem to the item. 选择项目:将MainList.SelectedItem设置为该项目。
  • Focus will be on the Button, but that should be ok, since it is inside the item. 焦点将放在Button上,但这应该没问题,因为它位于项目内部。
  • Find the selected item in second listbox: locating the ListBox in the DataTemplate is tricky, but you could set its IsSynchronizedWithCurrentItem property to True, and then use the underlying child collection's default CollectionView. 在第二个列表框中找到选定的项目:在DataTemplate中定位列表框很棘手,但是您可以将其IsSynchronizedWithCurrentItem属性设置为True,然后使用基础子集合的默认CollectionView。 You'd find the current item of MainList like above. 您会发现上面的MainList的当前项目。 Then you'd use: 然后,您将使用:

    itemToDelete = CollectionViewSource.GetDefaultView(item.ChildItems).CurrentItem; item.ChildItems.Remove(itemToDelete);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM