Reputation: 693
I have a situation with a ListBox control. Inside the item template there is a button. When I click the button I want to selected item of said ListBox to change to the item the button is in. At the moment, I can change the selected item by clicking elsewhere within the item template, but that doesn't work if I select the button. To clarify that last sentence for a commenter, if one clicks in the item template that is not the button, the SelectedItem will change as expected. If you click on the button within the item template, the SelectedItem will not change.
Further information: I am using MVVM and the button has attached to it a command within a view model. Any solution would need to allow this to continue to work.
The ListBox is linked to ItemSource, and the SelectedItem of the ListBox is bound to a property in the view model.
If there's a set way to do this, I've so far been unable to find it.
I am using C# and Visual Studio 2010.
Thanks.
Upvotes: 3
Views: 3370
Reputation: 159
C# version:
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);
}
Upvotes: 0
Reputation: 314
You can get the Listbox that is parent of the button using this function:
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
This is the code that selects the item. Add it to the Click event of the button:
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
Upvotes: 1
Reputation: 1549
A bit of your code would have been helpful, but here's a dummy example of how to do select a ListBoxItem
using a click on a button, through the MVVM pattern.
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;
}
}
Some XAML parts have been erased in order to keep it simple. Do not simply copy/paste this snippet, adapt it to your code.
<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>
I have not tested this code. So there might be some mistakes. Don't hesitate to point these out, and I will update my code.
EDIT : Here is the source code for my RelayCommand implementation (modified from 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);
}
}
Upvotes: 2
Reputation: 2363
If you can use ToggleButton
and Bind the IsChecked
to the ListBoxItem
IsSelected
property then it will be fine.
Reason because your ListBoxItem
is not selected is because the Button is handling MouseDown
event, thus making the ListBoxItem
unaware of the click. In your button create an event handler for Click
and set e.Handled = false;
.
Upvotes: 3