I have a ListView ItemsSource bound to an ObservableCollection. I added a property via MVVM to track the ListView.SelectedItem. A button was added to my ListView (via GridViewColumn.CellTemplate) to create a button command which displays data regarding each object in my ObservableCollection. So the list of objects in my ObservableCollection (ListView column 1) is shown in the ListView with a corresponding button (ListView column 2).
The Code works great! The only problem: the user must click the ListView row before clicking the corresponding button in the list. (I get a null reference exception on my "SelectedFromQueue" property if the user clicks the button without clicking the ListView row first.)
I would like to add code which sets the ListView.SelectedItem property when a button is clicked. So, if the user clicks a button, the code should update the ListView.SelectedItem property binding before the associated MVVM command is executed.
Does someone have any example code for this? Thanks for your help.
My XAML:
<UserControl xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.QueueObjectList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="290" Width="320">
<Grid Width="319">
<GroupBox Header="Queue Class List" HorizontalAlignment="Left" Width="319" BorderBrush="Black" BorderThickness="2">
<ListView ItemsSource="{Binding Path=QueueList}" Name="QueueListView">
<ListView.SelectedItem>
<Binding Path="SelectedFromQueue" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
</Binding>
</ListView.SelectedItem>
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Queue Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="179" Header="Property Information">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Get Property Info" Command="{Binding Path=GetQueueObjProperties}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</GroupBox>
</Grid>
</UserControl>
My MainWindowViewModel C# Code:
private ObservableCollection<Queue> _QueueList;
private Queue _selectedFromQueue;
public ObservableCollection<Queue> QueueList
{
get { return _QueueList; }
set
{
_QueueList = value;
RaisePropertyChanged("QueueList");
}
}
public Queue SelectedFromQueue
{
get { return _selectedFromQueue; }
set
{
_selectedFromQueue= value;
RaisePropertyChanged("SelectedFromQueue");
}
}
// Constructor
public MainWindowViewModel()
{
QueueList = new ObservableCollection<Queue>();
_selectedFromQueue= null;
}
public ICommand GetQueueObjProperties
{
get { return new RelayCommand(GetQueueProperties, CanGetQueueProperties); }
}
private bool CanGetQueueProperties()
{
if (_QueueList.Count > 0)
{
return true;
}
return false;
}
private void GetQueueProperties()
{
if (CanGetQueueProperties())
{
ResponseMessage.Add("Queue name: " +SelectedFromQueue.Name);
}
}
Update: Thanks sll!
I added the following to my XAML code:
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
</Style>
</ListView.Resources>
I added the following c# method to code behind:
protected void SelectCurrentItem(Object sender, KeyboardFocusChangedEventArgs e)
{
ListViewItem item = (ListViewItem)sender;
item.IsSelected = true;
}
Works great! Thanks again for the reference sll!
I'm not sure what GetQueueProperties
does, but it sounds that you use SelectedFromQueue
to know on what item to execute your logic and the selection in GUI is secondary.
If that's the case, don't use SelectedFromQueue
but add this to the Button
:
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
This will give you a Queue
object associated with the row of the pressed button as e.Parameter
in SelectedFromQueue
.
If you do need to set selected item for the GUI, at the start of SelectedFromQueue
add:
SelectedFromQueue = (e.Parameter is Queue) ? e.Parameter : null
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With