ListBox ItemTemplate中的按钮不选择项目

时间:2017-08-02 13:20:37

标签: c# wpf mvvm listbox selecteditem

我有一个ListBox控件的情况。在项目模板中有一个按钮。当我单击按钮时,我想要选择所述ListBox的项目以更改为按钮所在的项目。此时,我可以通过单击项目模板中的其他位置来更改所选项目,但如果我选择该项目则不起作用按钮。为了澄清评论者的最后一句话,如果单击非按钮的项目模板,SelectedItem将按预期更改。如果单击项模板中的按钮,SelectedItem将不会更改。

更多信息:我正在使用MVVM,并且按钮已在视图模型中附加了一个命令。任何解决方案都需要允许它继续工作。

ListBox链接到ItemSource,ListBox的SelectedItem绑定到视图模型中的属性。

如果有一套方法可以做到这一点,我到目前为止一直无法找到它。

我正在使用C#和Visual Studio 2010.

感谢。

4 个答案:

答案 0 :(得分:1)

如果您可以使用ToggleButton并将IsChecked绑定到ListBoxItem IsSelected属性,那就没问题了。
原因是因为未选择ListBoxItem是因为Button正在处理MouseDown事件,因此ListBoxItem不知道点击。在您的按钮中为Click创建一个事件处理程序并设置e.Handled = false;

答案 1 :(得分:1)

您的一些代码会有所帮助,但这是一个虚拟示例,说明如何通过MVVM模式单击按钮来选择ListBoxItem

public class MyViewModel : BaseViewModel // implements INotifyPropertyChanged
{
    private ICommand _myCommand;

    public ICommand MyCommand { get {return _myCommand;} private set { _myCommand = value; OnPropertyChanged(); }}

    private ObservableCollection<int> _myObjects;

    public ObservableCollection<int> MyObjects { get {return _myObjects;} private set {_myObjects = value; OnPropertyChanged();}}

    private int _mySelectedObject;

    public int MySelectedObject { get {return _mySelectedObject;} set {_mySelectedObject = value; OnPropertyChanged(); }}

    public MyViewModel 
    {
        MyCommand = new RelayCommand(SetSelectedObject); // the source code for RelayCommand may be found online.
    }

    private void SetSelectedObject(object obj) 
    {
        int myInt = (int)obj;

        MySelectedObject = myInt;
    }
}

为了保持简单,已删除了一些XAML部件。不要简单地复制/粘贴此代码段,使其适应您的代码。

<UserControl x:Name="root" DataContext="{Binding MyViewModel, Source={StaticResource Locator.MyViewModel}}">
    <ListBox ItemsSource="{Binding MyObjects}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding }"/>
                    <Button Command="{Binding MyCommand, ElementName=root}" CommandParameter="{Binding }"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</UserControl>

我还没有测试过这段代码。所以可能会有一些错误。不要犹豫,指出这些,我会更新我的代码。

编辑:以下是我的RelayCommand实现的源代码(从Telerik修改):

public class RelayCommand : ICommand
{
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    private Action<object> _methodToExecute;
    private Func<object, bool> _canExecuteEvaluator;

    public RelayCommand(Action<object> methodToExecute, Func<object, bool> canExecuteEvaluator)
    {
        _methodToExecute = methodToExecute;
        _canExecuteEvaluator = canExecuteEvaluator;
    }

    public RelayCommand(Action<object> methodToExecute)
        : this(methodToExecute, null)
    {
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecuteEvaluator == null)
        {
            return true;
        }
        else
        {
            bool result = _canExecuteEvaluator.Invoke(parameter);
            return result;
        }
    }

    public void Execute(object parameter)
    {
        _umethodToExecute.Invoke(parameter);
    }
}

答案 2 :(得分:0)

使用此功能,您可以获取作为按钮父级的列表框:

    Function GetParent(child As UIElement, parentType As Type) As UIElement
        If child Is Nothing Then Return Nothing
        Dim p = child
        Do
            p = TryCast(VisualTreeHelper.GetParent(p), UIElement)
            If p Is Nothing Then Return Nothing
            If p.GetType Is parentType Then Return p
        Loop
    End Function

这是选择项目的代码。将其添加到按钮的Click事件:

Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
  Dim lst As ListBox = GetParent(sender, GetType(ListBox))
  lst.SelectedIndex = lst.Items.IndexOf(Me.DataContext)
End Sub

答案 3 :(得分:0)

C# 版本:

  private void Button_Click(object sender, RoutedEventArgs e)
    {
        Button b = sender as Button;
        TListBoxItems data = b.DataContext as TListBoxItems;
        ListBox aLB = new ListBox();
        aLB = (ListBox)GetParent(sender, aLB.GetType());
        aLB.SelectedIndex = aLB.Items.IndexOf(data);
    }

    public object GetParent(object child, Type parentType)
    {
        if (child == null)
            return null/* TODO Change to default(_) if this is not a reference type */;
        var p = child;
        do
        {
            p = VisualTreeHelper.GetParent((UIElement)p) as UIElement;
            if (p == null)
                return null/* TODO Change to default(_) if this is not a reference type */;
            if (p.GetType() == parentType)
                return p;
        }
        while (true);
    }