How can I get the selected item from clicking a context menu bound to a listview control in WPF?
This is my markup:
<ListView Name="lvCustomerJobs">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Click="cmCustomerRemoveJob"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},
Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
</ListView.ContextMenu>
<ListView.View>
<GridView>
<GridViewColumn Header="Status" Width="150" DisplayMemberBinding="{Binding Status}" />
<GridViewColumn Header="Booked in by" Width="150" DisplayMemberBinding="{Binding BookedInBy}" />
<GridViewColumn Header="Date Required" Width="150" DisplayMemberBinding="{Binding DateRequired}" />
</GridView>
</ListView.View>
</ListView>
This is my code behind:
private void cmCustomerRemoveJob(object sender, RoutedEventArgs e)
{
var item = ((FrameworkElement)e.OriginalSource).DataContext as User;
if (item != null)
{
MessageBox.Show(item.DateRequired + " Item's Double Click handled!");
}
}
But item IS null?
You should cast sender object to MenuItem and then use CommandParameter like this:
private void cmCustomerRemoveJob(object sender, RoutedEventArgs e)
{
var item = ((MenuItem)sender).CommandParameter as User;
if (item != null)
{
MessageBox.Show(item.DateRequired + " Item's Double Click handled!");
}
}
I bind my ListView to a collection in the model and bind the SelectedItem to the model as well.
<ListView ItemSource="{Binding CustomerCollection}" SelectedItem="{Binding SelectedCustomer}">
Then, my command method can reference SelectedCustomer as needed.
If this isn't ideal for some reason, I'd love to know!
Related
How can I bind the listview Item Properties of a selected item?
At the left side I show my files with sites in the listview and at the right i want to show the name, number of sites etc in a kind of Infobox (Grid with labels).
So how can I bind the list[index].name to the name label when i select it in the listview?
Or should I work with Selection Changed Event?
You Could bind the SelectedItem property of the GridView to your property on the ViewModel:
<DataGrid SelectedItem="{Binding SelectedItem, Mode=TwoWay}" >
.....
</DataGrid>
and in SelectedItem property:
private YourItemType_selectedItem;
public YourItemType SelectedItem
{
get { return _selectedItem; }
set
{
if(value != _selectedItem)
{
_selectedItem = value;
NotifyOfPropertyChange("SelectedItem");
// notify InfoBox property changed
NotifyOfPropertyChange("InfoBoxItem");
}
}
}
You could bind the TextBlocks/TextBoxes in the InfoBox to the SelectedItem property of the ListView.
Give the ListView an x:Name:
<ListView x:Name="listView">
<ListView.View>
<GridView>
<GridViewColumn Width="160" DisplayMemberBinding="{Binding Pos}" Header="Pos." />
<GridViewColumn Width="160" DisplayMemberBinding="{Binding Name}" Header="Name" />
<GridViewColumn Width="160" DisplayMemberBinding="{Binding Seitenzahl}" Header="Seitenzahl" />
</GridView>
</ListView.View>
</ListView>
...and use use an ElementName binding:
<TextBlock Text="{Binding SelectedItem.Name, ElementName=listView}" />
<TextBlock Text="{Binding SelectedItem.Pos, ElementName=listView}" />
<TextBlock Text="{Binding SelectedItem.Seitenzahl, ElementName=listView}" />
"Name", "Pos" and "Seitenzahl" are the name of the same properties that you bind to and display in the columns of the ListView.
Hi i'm working in windows store app with MVVM pattern and i have some problem in catch the listview itemclick value in relay command. Now i got the selected item value.But don't know how to get itemclickValue. Here i have attach my code.
XAML
<ListView x:Name="lstItem" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding ItemList}" Padding="130,0,0,0" SelectedItem="{Binding SelectedItem,Mode=TwoWay}">
<Triggers:Interactions.Triggers>
<Triggers:EventTrigger EventName="SelectionChanged">
<Triggers:InvokeCommandAction Command="{Binding SelectedItemCommand}" CommandParameter="{Binding SelectedItem,Mode=TwoWay}"/>
</Triggers:EventTrigger>
</Triggers:Interactions.Triggers>
</ListView>
ViewModel Code
private Item _selectedItem;
public Item SelectedItem { get { return _selectedItem; } set { _selectedItem = value; NotifyPropertyChanged("SelectedTrends"); } }
private RelayCommand<Item> _selectedItemCommand;
public RelayCommand<Item> SelectedItemCommand
{
get
{
return this._selectedItemCommand
?? (this._selectedItemCommand= new RelayCommand<Item>(item=>
{
MessageDialog messagedialog = new MessageDialog(item.Name,"Test");
messagedialog.ShowAsync();
}));
}
}
There's a bit of redundancy here:
Option 1: Spare the CommandParameter:
private Item _selectedItem;
public Item SelectedItem
{
get { return _selectedItem; }
set { _selectedItem = value; NotifyPropertyChanged("SelectedTrends"); }
}
private RelayCommand _selectedItemCommand;
public RelayCommand SelectedItemCommand
{
get
{
return this._selectedItemCommand
?? (this._selectedItemCommand= new RelayCommand(() =>
{
MessageDialog messagedialog = new MessageDialog(selectedItem.Name,"Test");
messagedialog.ShowAsync();
}));
}
}
and the XAML:
<ListView x:Name="lstItem" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding ItemList}" SelectedItem="{Binding SelectedItem,Mode=TwoWay}" Padding="130,0,0,0">
<Triggers:Interactions.Triggers>
<Triggers:EventTrigger EventName="SelectionChanged">
<Triggers:InvokeCommandAction Command="{Binding SelectedItemCommand}" />
</Triggers:EventTrigger>
</Triggers:Interactions.Triggers>
</ListView>
Option 2: Spare the SelectedItem binding:
<ListView x:Name="lstItem" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding ItemList}" Padding="130,0,0,0">
<Triggers:Interactions.Triggers>
<Triggers:EventTrigger EventName="SelectionChanged">
<Triggers:InvokeCommandAction Command="{Binding SelectedItemCommand}" CommandParameter="{Binding SelectedItem, ElementName=lstItem}"/>
</Triggers:EventTrigger>
</Triggers:Interactions.Triggers>
</ListView>
and remove the SelectedItem property from the ViewModel, unless you need it for something else.
EDIT
If you want to handle the click event on an item, you need to move the behavior to the ItemTemplate DataTemplate parent control, for example the grid in which the controls are placed. This lets you handle the click event on the item.
To resolve the problem I evaluated the setter attributed if there is Null reference. Then it worked fine and the event wasn't thrown anymore choose other elements.
<ListView Name="lstView" ItemsSource="{Binding Path=SimResults}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedItemCommand}" CommandParameter="{Binding SelectedItem, ElementName=lstView}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="FileUniqueID" Width="Auto" DisplayMemberBinding="{Binding Path=FileUniqueID}" />
<GridViewColumn Header="XML" Width="Auto" DisplayMemberBinding="{Binding Path=XML}" />
<GridViewColumn Header="Request" Width="Auto" HeaderStringFormat="" DisplayMemberBinding="{Binding Path=RequestShort}" />
<GridViewColumn Header="RequestDate" Width="Auto" DisplayMemberBinding="{Binding Path=RequestDate}" />
<GridViewColumn Header="Response" Width="Auto" DisplayMemberBinding="{Binding Path=ResponseShort}" />
<GridViewColumn Header="ResponseDate" Width="Auto" DisplayMemberBinding="{Binding Path=ResponseDate}" />
<GridViewColumn Header="ResendCounter" Width="Auto" DisplayMemberBinding="{Binding Path=ResendCounter}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
I would like to be able to select an item that is bound to my gridview and press the delete button, which would delete the item from the observable collection to which the gridview is bound to.
<ListView Height="166" HorizontalAlignment="Left" Margin="12,290,0,0" Name="listView1" VerticalAlignment="Top" Width="636" ItemsSource="{Binding SearchTerms}" KeyUp="SearchTermsGrid_KeyPressed">
<ListView.View>
<GridView x:Name="SearchTermsGrid">
<GridViewColumn Width="155" Header="Search Term" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="90" Header="Status" DisplayMemberBinding="{Binding Status}"/>
<GridViewColumn Width="60" Header="Count" DisplayMemberBinding="{Binding NumberToDownload}"/>
<GridViewColumn Width="60" Header="Size" DisplayMemberBinding="{Binding Size}"/>
<GridViewColumn Width="60" Header="Type" DisplayMemberBinding="{Binding Type}"/>
</GridView>
</ListView.View>
</ListView>
ObservableCollection<SearchTerm> _searchTerms = new ObservableCollection<SearchTerm>();
public ObservableCollection<SearchTerm> SearchTerms
{
get
{
return _searchTerms;
}
}
private void SearchTermsGrid_KeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
//I dunno, this might be a bad approach.
}
}
does this not work:?
this._searchTerms.Remove(this.listView1.SelectedItem);
I'm trying to use the event trigger from Blend to fire a button click event of a listview item, it should work so that the item does not have to be selected for the relevant row to be referenced.
My code is...
Public void MyCommand(object obj)
{
// the tag of this has the search type
ListViewItem item = obj as ListViewItem;
// do my dreary domain work...
}
my xaml is...
<ListView ItemsSource="{Binding Path=SystemSetupItems}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
MinHeight="120" >
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding Description}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseClick">
<i:InvokeCommandAction CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem, AncestorLevel=1}}" Command="{Binding MyCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
but this doesn't work at all, alternatively I can do this in my xaml button definition
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding OpenWorkSpaceCommand}" CommandParameter="{Binding Path=Name}" Content="Edit..." DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}}" >
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
but this required the listview item to be previously selected, which is not the behaviour I want.
For my DataGrid I have a button on each item using the cell template. Each item is an object of type Meal. In my Meal.cs file I have an event definition like so:
public Meal()
{
RemoveMealCommand = new RelayCommand(() => RemoveMealCommandExecute());
}
public RelayCommand RemoveMealCommand
{
get;
set;
}
public delegate void RemoveMealEventHandler(object sender, EventArgs e);
public event RemoveMealEventHandler RemoveMealEvent;
private void RemoveMealCommandExecute()
{
RemoveMealEvent(this, null);
}
In my viewmodel for every meal in my list I can just add a handler to that event. And for my xaml button I just set the command to the Meal's RelayCommand.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding Path=RemoveMealCommand}">
<Image Width="13" Height="13" Source="/Images/delete-icon.png"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Now when you click the button the Meal is responsible for firing the event and the viewmodel is responsible for handling it.
This code generates a Listview with a grid, of multiple name and emails inside TextBox control. I would like to know how can I capture the focus event on one of the TextBox of a row to have the entire ListView row to be selected.
<ListView Name="lstRecipients" ItemsSource="{Binding Path=Recipients}">
<ListView.Resources>
<DataTemplate x:Key="tbNameTemplate">
<TextBox Name="tbName" Text="{Binding Path=Username, ValidatesOnDataErrors=True}"/>
</DataTemplate>
<DataTemplate x:Key="tbEmailTemplate">
<TextBox Name="tbEmail" Text="{Binding Path=Email, ValidatesOnDataErrors=True}"/>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView x:Name="gvRecipients">
<GridViewColumn Header="Name" CellTemplate="{StaticResource tbNameTemplate}"/>
<GridViewColumn Header="Email" CellTemplate="{StaticResource tbEmailTemplate}"/>
</GridView>
</ListView.View>
</ListView>
You can add a handler to the GotFocus event on the TextBox that sets the selected item on the ListView. You can use ItemsControl.ContainerFromElement to get the ListViewItem and ItemContainerGenerator.ItemFromContainer to get the bound data object. In XAML:
<TextBox GotFocus="tbName_GotFocus" Name="tbName" Text="{Binding Path=Username, ValidatesOnDataErrors=True}"/>
In code-behind:
private void tbName_GotFocus(object sender, RoutedEventArgs e)
{
var container = lstRecipients.ContainerFromElement((DependencyObject)sender);
if (container != null)
{
lstRecipients.SelectedItem = lstRecipients.ItemContainerGenerator
.ItemFromContainer(container);
}
}
You could also set the handler on the ListView, since GotFocus is a routed event. You could use this to create a handler that could be shared between ListViews. In XAML:
<ListView GotFocus="lstRecipients_GotFocus" Name="lstRecipients" ItemsSource="{Binding Path=Recipients}">
In code-behind:
private void lstRecipients_GotFocus(object sender, RoutedEventArgs e)
{
var selector = sender as Selector;
if (selector != null)
{
var container = selector.ContainerFromElement
((DependencyObject)e.OriginalSource);
if (container != null)
{
selector.SelectedItem = selector.ItemContainerGenerator
.ItemFromContainer(container);
}
}
}
(If you don't want the TextBox to be editable at all, you could also just set Focusable="False" or use a TextBlock instead of a TextBox and focus would go to the ListView and select the row when the cell was clicked.)