Кнопка внутри ListBox ItemTemplate не выбирает элемент
У меня ситуация с элементом управления ListBox. Внутри шаблона элемента есть кнопка. Когда я нажимаю кнопку, я хочу, чтобы выбранный элемент указанного ListBox изменился на элемент, в котором находится кнопка. В настоящий момент я могу изменить выбранный элемент, щелкнув в другом месте в шаблоне элемента, но это не сработает, если я выберу кнопка. Чтобы уточнить последнее предложение для комментатора, если один щелкнет шаблон элемента, который не является кнопкой, SelectedItem изменится, как и ожидалось. Если вы нажмете кнопку в шаблоне элемента, SelectedItem не изменится.
Дополнительная информация: я использую MVVM, и к кнопке прикреплена команда в модели представления. Любое решение должно позволить этому продолжать работать.
ListBox связан с ItemSource, а SelectedItem ListBox связан со свойством в модели представления.
Если есть определенный способ сделать это, я пока не смог его найти.
Я использую C# и Visual Studio 2010.
Благодарю.
4 ответа
Если вы можете использовать ToggleButton
и связать IsChecked
к ListBoxItem
IsSelected
собственность тогда будет хорошо.
Причина, потому что ваш ListBoxItem
не выбран, потому что кнопка обрабатывает MouseDown
событие, таким образом, делая ListBoxItem
не знают о клике. В вашей кнопке создайте обработчик событий для Click
и установить e.Handled = false;
,
Немного вашего кода было бы полезно, но вот пример того, как сделать выбор ListBoxItem
используя щелчок по кнопке через шаблон MVVM.
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);
}
}
Вы можете получить Listbox, который является родительским для кнопки, используя эту функцию:
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
С# версия:
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);
}