ListBox ItemTemplate 中的按钮未选择项目
Button within ListBox ItemTemplate not selecting item
我遇到了 ListBox 控件的情况。在项目模板内有一个按钮。当我单击按钮时,我想 selected 所述 ListBox 的项目更改为按钮所在的项目。目前,我可以通过单击项目模板中的其他位置来更改 selected 项目,但如果我 select 按钮,那将不起作用。为了向评论者澄清最后一句话,如果在不是按钮的项目模板中单击,则 SelectedItem 将按预期更改。如果您单击项目模板中的按钮,SelectedItem 将不会更改。
更多信息:我正在使用 MVVM,并且按钮在视图模型中附加了一个命令。任何解决方案都需要允许它继续工作。
ListBox 链接到 ItemSource,ListBox 的 SelectedItem 绑定到视图模型中的一个 属性。
如果有固定的方法可以做到这一点,我目前还没有找到。
我正在使用 C# 和 Visual Studio 2010。
谢谢。
如果你可以使用 ToggleButton
并将 IsChecked
绑定到 ListBoxItem
IsSelected
属性 就可以了。
您的 ListBoxItem
未被选中的原因是按钮正在处理 MouseDown
事件,从而使 ListBoxItem
不知道点击。在您的按钮中为 Click
创建一个事件处理程序并设置 e.Handled = false;
.
您的一些代码会有所帮助,但这里有一个虚拟示例,说明如何通过 MVVM 模式通过单击按钮来执行 select 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 部分已被删除,以保持简单。不要简单地 copy/paste 此代码段,使其适应您的代码。
<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);
}
}
您可以使用此函数获取作为按钮父级的列表框:
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
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);
}
我遇到了 ListBox 控件的情况。在项目模板内有一个按钮。当我单击按钮时,我想 selected 所述 ListBox 的项目更改为按钮所在的项目。目前,我可以通过单击项目模板中的其他位置来更改 selected 项目,但如果我 select 按钮,那将不起作用。为了向评论者澄清最后一句话,如果在不是按钮的项目模板中单击,则 SelectedItem 将按预期更改。如果您单击项目模板中的按钮,SelectedItem 将不会更改。
更多信息:我正在使用 MVVM,并且按钮在视图模型中附加了一个命令。任何解决方案都需要允许它继续工作。
ListBox 链接到 ItemSource,ListBox 的 SelectedItem 绑定到视图模型中的一个 属性。
如果有固定的方法可以做到这一点,我目前还没有找到。
我正在使用 C# 和 Visual Studio 2010。
谢谢。
如果你可以使用 ToggleButton
并将 IsChecked
绑定到 ListBoxItem
IsSelected
属性 就可以了。
您的 ListBoxItem
未被选中的原因是按钮正在处理 MouseDown
事件,从而使 ListBoxItem
不知道点击。在您的按钮中为 Click
创建一个事件处理程序并设置 e.Handled = false;
.
您的一些代码会有所帮助,但这里有一个虚拟示例,说明如何通过 MVVM 模式通过单击按钮来执行 select 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 部分已被删除,以保持简单。不要简单地 copy/paste 此代码段,使其适应您的代码。
<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);
}
}
您可以使用此函数获取作为按钮父级的列表框:
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
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);
}