I have a ListPicker in an application page, but the SelectionChanged event gets called multiple times as the page loads. To avoid this, I have been following a previous question I asked here ListPicker SelectionChanged Event Called Multiple Times During Navigation in which the suggestion was instead of making ThemeListPicker_SelectionChanged make a parent stackpanel inside the datatemplate..', create a tap event in the StackPanel called stk_Tap, and 'use this tap stk_Tap to do your action as, this event would also get called every time the selection changed gets called but, it wont exhibit the buggy behavior like that of selection changed event'
Now I have adjusted my solution accordingly, but I do not know how to determine which item of the ListPicker is being selected or is currently selected. Also I removed the ListPicker SelectionChanged event in the ListPicker because I thought the StackPanel could get the item, but I am not sure if this is correct or how to do this?
XAML
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Name="PickerItemTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<toolkit:ListPicker x:Name="ThemeListPicker" Header="Theme"
ItemTemplate="{StaticResource PickerItemTemplate}"
SelectionChanged="ThemeListPicker_SelectionChanged"/>
XAML.CS
private void ThemeListPicker_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if(ThemeListPicker.SelectedIndex != -1)
{
var theme = (sender as ListPicker).SelectedItem;
if (index == 0)
{
Settings.LightTheme.Value = true;
MessageBox.Show("light");
}
else
{
Settings.LightTheme.Value = false;
MessageBox.Show("dark");
}
}
}
*EDIT: How I updated my solution
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Name="PickerItemTemplate">
<StackPanel tap="stk_Tap">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<toolkit:ListPicker x:Name="ThemeListPicker" Header="Theme"
ItemTemplate="{StaticResource PickerItemTemplate}"
/>
So, even when I left the ListPicker SelectionChanged event in the code behind after making the modifications, I did not see the event being called twice upon the page loading/navigating to, but I am not sure how to get the currently selected item now?
EDIT2**
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
themeList = new List<TestApp.Common.Theme>();
themeList.Add(new TestApp.Common.Theme() { Name = "Darker", name = "dark" });
themeList.Add(new TestApp.Common.Theme() { Name = "Lighter", name = "light" });
ThemeListPicker.ItemsSource = themeList;
}
private void stk_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if (ThemeListPicker.SelectedIndex != -1)
{
//Need to get the current ThemeListPicker's 'name'
var selectedItem1 = (sender as StackPanel).DataContext as ListPicker;
//use selectedItem1
}
}
No need to extra tap event for such kind of work.
private void ThemeListPicker_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if(ThemeListPicker.SelectedIndex==-1)
return;
var theme = (sender as ListPicker).SelectedItem;
if (index == 0)
{
Settings.LightTheme.Value = true;
MessageBox.Show("light");
}
else
{
Settings.LightTheme.Value = false;
MessageBox.Show("dark");
}
ThemeListPicker.SelectedIndex=-1
}
ListPicker SelectionChanged Event Called Multiple Times During Navigation
for above problem if i guess right you set listpicker's itemssource on OnNavigatedTo event. so modify you r onNavigatedTo method with
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode != NavigationMode.Back)
{
// Your code goes here
}
}
//Stack panel tap event
private void stack_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var selectedIrem = (Cast as your type)(sender as StackPanel).DataContext;
}
I have a longlistselector like the below image. now I wanna get the text of the item user's tapped. I've searched a lot but no solution found ;(
pay attention to the image please to give a sample code
http://amiryari.persiangig.com/image/stackoverflow-question.jpg
1) Wire up the SelectionChanged event on the LongListSelector control:
<phone:LongListSelector ItemsSource="{Binding MyListItems}"
SelectionChanged="LongListSelector_SelectionChanged">
2) Retrieve the selected item from the AddedItems collection in the SelectionChangedEventArgs:
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
var item = e.AddedItems[0];
}
}
3) If your item is an object, and the text is displayed through a property, then you would have access to the text through the property on your object:
MyListItemObject item = e.AddedItems[0] as MyListItemObject;
MessageBox.Show(item.FullName);
If your list is bound to a list of strings, then it would simply be the first item in the AddedItems collection:
string fullName = e.AddedItems[0].ToString();
MessageBox.Show(fullName);
You can always listen for the SelectionChanged event and obtain the string. There is another way if you are using a DataTemplate to style your items in the list. Declare Tapped event in DataTemplate like this:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ContactImage}"/>
<TextBlock x:Name="NameTextBlock" Text="{Binding ContactName}" Tapped="NameTextBlock_Tapped"/>
</StackPanel>
</DataTemplate/>
Now in our code:
private void LongListSelector_SelectionChanged(object sender, BlahBlah e)
{
var tb = sender as Textblock;
string cName = tb.Text; //This is the string you wanted.
MessageBox.Show(cName);
}
I am developping a small WPF application which consist mostly in displaying ObservableCollection<> in others ObservableCollection<>, and so on.
Here is a code example of what my application looks like:
<Listbox Name="MainList" ItemsSource={Binding}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Textblock Text={Binding MainName} />
<Button>Add item</Button>
<Button>Delete item</Button>
<Listbox Name="ChildList" ItemsSource="{Binding Path=ChildItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<Textblock Text={Binding ChildName} />
</DataTemplate>
</ListBox.ItemTemplate>
</Listbox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</Listbox>
And visually it pretty much looks like this:
EDIT:
I will re-explain what I am trying to do.
Whenever I click Button A or Button B I want to Select the MainList ListBoxItem in which they are contained (i.e: A Item)
And in a second time whenever I click Button B:
I want to be sure that a ListBoxItem is selected in ChildList(Second Listbox in the picture)
And if so, I want to delete it in code-behind.
But my main problem is since everything is generated by my bindings I cannot get, so far, an element from my ChildList because ChildList is duplicated in any of my MainList ListBoxItem.
If I understand well the problem is that you want first click on a button of unselected item to select the MainItem, and on next click, when MainItem is already selected, preform click action. Try this when button is clicked:
private ListBoxItem FindItemContainer(DependencyObject obj)
{
while (obj != null && !(obj is ListBoxItem))
{
obj = VisualTreeHelper.GetParent(obj);
}
if (obj != null)
return obj as ListBoxItem;
else
return null;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var lbi = FindItemContainer(sender as DependencyObject);
if (lbi != null)
{
if (lbi.IsSelected)
{
//do click event
}
else
lbi.IsSelected = true;
}
}
Of course you can also do it more MVVM way by binding ListBoxItem.IsSelected to lets say bool MainItem.MyItemIsSelected
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=MyItemIsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
and Button.Command to your ICommand MainItem.DeleteCommand and then when command is executed do something like that:
if (MyItemIsSelected)
{
//do command body
}
else
MyItemIsSelected = true;
which will be better long term because you could replicate SelectedItem behaviour in ChildList object (add MyItemIsSelected and bind it to inner 'ListBoxItem.IsSelected, like discribed above) and add MySelectedItem property to ChildList:
ChildItem MySelectedItem
{
get
{
return Items.FirstOrDefault(n=>n.MyItemIsSelected);
}
}
and your delete command would look like this:
if (MyItemIsSelected)
{
ChildItem selItem = ChildItems.MySelectedItem;
if (selItem != null) ChildItems.Items.Remove(selItem);
}
else
MyItemIsSelected = true;
if everything is data bound and lists are ObservableCollections then you can do all that in object and UI will follow. Actually you can do only this child selection binding bit and still use first solution and in Button_Click look like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
var lbi = FindItemContainer(sender as DependencyObject);
if (lbi != null)
{
if (lbi.IsSelected)
{
MainItem mainItem = lbi.Content as MainItem;
ChildItem selChild = mainItem.ChildItems.MySelectedItem;
if (selChild != null) mainItem.ChildItems.Items.Remove(selChild);
}
else
lbi.IsSelected = true;
}
}
Here is simple, working example on Dropbox
You can do everything you want to do in code behind:
Find the item on which the Button is pressed: in the click-event, cast the sender parameter to type Button. Its DataContext property will contain the item you want to select.
Select the item: set MainList.SelectedItem to the item.
Focus will be on the Button, but that should be ok, since it is inside the item.
Find the selected item in second listbox: locating the ListBox in the DataTemplate is tricky, but you could set its IsSynchronizedWithCurrentItem property to True, and then use the underlying child collection's default CollectionView. You'd find the current item of MainList like above. Then you'd use:
itemToDelete = CollectionViewSource.GetDefaultView(item.ChildItems).CurrentItem;
item.ChildItems.Remove(itemToDelete);
I was wondering how I could update a filter on a CollectionViewSource with a ComboBox.
I have the following code:
<CollectionViewSource x:Key="cvsCars"
Source="{Binding Source={StaticResource odpCars}}">
<ComboBox Name="cbxMake" Margin="5" IsEnabled="False" />
I'm sure I need some sort of a SelectionChanged event for the ComboBox but I can't figure out a way to make it work with this code.
private void MakeFilterOn(object sender, RoutedEventArgs e)
{
cbxMake.IsEnabled = true;
cvsCars.Filter += new FilterEventHandler(cvsCars_Filter);
}
void cvsCars_Filter(object sender, FilterEventArgs e)
{
Car car = e.Item as Car;
if (car != null)
{
if (car.Maker.ToString() == cbxMake.SelectedItem.ToString())
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
}
Any advice is greatly appreciated.
The CollectionViewSource is populated by an ObjectDataProvider. The updates will be applied to a ListBox. MakeFilterOn is a CheckBox.
You'll have to refresh your CollectionViewSource's View...so, in your handler for your combobox's SelectionChanged event, refresh your cvs:
cvsCars.View.Refresh();
You may want to look into the databinding powers of WPF and then later, the Model View ViewModel (MVVM) "pattern". That way, you can bind the combobox's SelectedItem to a property on your window's DataContext and eliminate the need for handling the SelectionChanged event.
What do I need to do in order to reference the double click event for a listview control?
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="MouseDoubleClick" Handler="listViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
The only difficulty then is if you are interested in the underlying object the listviewitem maps to e.g.
private void listViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListViewItem item = sender as ListViewItem;
object obj = item.Content;
}
I'm using something like this to only trigger on ListViewItem double-click and not for example when you double-click on the header of the ListView.
private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
DependencyObject obj = (DependencyObject)e.OriginalSource;
while (obj != null && obj != myListView)
{
if (obj.GetType() == typeof(ListViewItem))
{
// Do something here
MessageBox.Show("A ListViewItem was double clicked!");
break;
}
obj = VisualTreeHelper.GetParent(obj);
}
}
Use the ListView.HitTest method
private void listView_MouseDoubleClick(object sender, MouseEventArgs e)
{
var senderList = (ListView) sender;
var clickedItem = senderList.HitTest(e.Location).Item;
if (clickedItem != null)
{
//do something
}
}
Or the old way
private void listView_MouseDoubleClick(object sender, MouseEventArgs e)
{
var senderList = (ListView) sender;
if (senderList.SelectedItems.Count == 1 && IsInBound(e.Location, senderList.SelectedItems[0].Bounds))
{
//Do something
}
}
public bool IsInBound(Point location, Rectangle bound)
{
return (bound.Y <= location.Y &&
bound.Y + bound.Height >= location.Y &&
bound.X <= location.X &&
bound.X + bound.Width >= location.X);
}
private void positionsListView_DoubleClick(object sender, EventArgs e)
{
if (positionsListView.SelectedItems.Count == 1)
{
ListView.SelectedListViewItemCollection items = positionsListView.SelectedItems;
ListViewItem lvItem = items[0];
string what = lvItem.Text;
}
}
I don't yet have a large enough reputation score to add a comment where it would be most helpful, but this is in relation to those asking about a .Net 4.5 solution.
You can use the mouse X and Y co-ordinates and the ListView method GetItemAt to find the item which has been clicked on.
private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListViewItem item = myListView.GetItemAt(e.X, e.Y)
// Do something here
}
I needed that as well. I found that on msdn:
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.activation.aspx
I think this delegate is for that.
for me, I do double click of ListView in this code section .
this.listView.Activation = ItemActivation.TwoClick;
this.listView.ItemActivate += ListView1_ItemActivate;
ItemActivate specify how user activate with items
When user do double click, ListView1_ItemActivate will be trigger.
Property of ListView ItemActivate refers to access the collection of items selected.
private void ListView1_ItemActivate(Object sender, EventArgs e)
{
foreach (ListViewItem item in listView.SelectedItems)
//do something
}
it works for me.
I found this on Microsoft Dev Center. It works correctly and ignores double-clicking in wrong places. As you see, the point is that an item gets selected before double-click event is triggered.
private void listView1_DoubleClick(object sender, EventArgs e)
{
// user clicked an item of listview control
if (listView1.SelectedItems.Count == 1)
{
//do what you need to do here
}
}
http://social.msdn.microsoft.com/forums/en-US/winforms/thread/588b1053-8a8f-44ab-8b44-2e42062fb663
Here is how to get the selected object and object matching code for the double clicked listview item in a WPF listview:
/// <summary>
/// Get the object from the selected listview item.
/// </summary>
/// <param name="LV"></param>
/// <param name="originalSource"></param>
/// <returns></returns>
private object GetListViewItemObject(ListView LV, object originalSource)
{
DependencyObject dep = (DependencyObject)originalSource;
while ((dep != null) && !(dep.GetType() == typeof(ListViewItem)))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return null;
object obj = (Object)LV.ItemContainerGenerator.ItemFromContainer(dep);
return obj;
}
private void lvFiles_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
object obj = GetListViewItemObject(lvFiles, e.OriginalSource);
if (obj.GetType() == typeof(MyObject))
{
MyObject MyObject = (MyObject)obj;
// Add the rest of your logic here.
}
}
You can get the ListView first, and then get the Selected ListViewItem.
I have an example for ListBox, but ListView should be similar.
private void listBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListBox box = sender as ListBox;
if (box == null) {
return;
}
MyInfo info = box.SelectedItem as MyInfo;
if (info == null)
return;
/* your code here */
}
e.Handled = true;
}
Either use the MouseDoubleClick event, and also, all the MouseClick events have a click count in the eventargs variable 'e'. So if e.ClickCount == 2, then doubleclicked.
In the ListBox DoubleClick event get the selecteditem(s) member of the listbox, and there you are.
void ListBox1DoubleClick(object sender, EventArgs e)
{
MessageBox.Show(string.Format("SelectedItem:\n{0}",listBox1.SelectedItem.ToString()));
}
It's annoying, but the best way to do it is something like:
<DataTemplate Name="MyCoolDataTemplate">
<Grid Loaded="HookLVIClicked" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
<!-- your code here -->
</Grid>
</DataTemplate>
Then in the code:
public void HookLVIClicked(object sender, RoutedEventArgs e) {
var fe = (FrameworkElement)sender;
var lvi = (ListViewItem)fe.Tag;
lvi.MouseDoubleClick += MyMouseDoubleClickHandler;
}
Was having a similar issue with a ListBox wanting to open a window (Different View) with the SelectedItem as the context (in my case, so I can edit it).
The three options I've found are: 1. Code Behind 2. Using Attached Behaviors 3. Using Blend's i:Interaction and EventToCommand using MVVM-Light.
I went with the 3rd option, and it looks something along these lines:
<ListBox x:Name="You_Need_This_Name"
ItemsSource="{Binding Your_Collection_Name_Here}"
SelectedItem="{Binding Your_Property_Name_Here, UpdateSourceTrigger=PropertyChanged}"
... rest of your needed stuff here ...
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Command:EventToCommand Command="{Binding Your_Command_Name_Here}"
CommandParameter="{Binding ElementName=You_Need_This_Name,Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
That's about it ... when you double click on the item you want, your method on the ViewModel will be called with the SelectedItem as parameter, and you can do whatever you want there :)
The sender is of type ListView not ListViewItem.
private void listViewTriggers_MouseDoubleClick(object sender, MouseEventArgs e)
{
ListView triggerView = sender as ListView;
if (triggerView != null)
{
btnEditTrigger_Click(null, null);
}
}
i see this subject is high on google, there is my simple and working sample :)
XAML:
<ListView Name="MainTCList" HorizontalAlignment="Stretch" MinHeight="440" Height="Auto" Margin="10,10,5.115,4" VerticalAlignment="Stretch" MinWidth="500" Width="Auto" Grid.Column="0" MouseDoubleClick="MainTCList_MouseDoubleClick" IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn Header="UserTID" DisplayMemberBinding="{Binding UserTID}" Width="80"/>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Title}" Width="410" />
</GridView>
</ListView.View>
</ListView>
C#
private void MainTCList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TC item = (TC)MainTCList.Items.CurrentItem;
Wyswietlacz.Content = item.UserTID;
}
Wyswietlacz is a test Label to see item content :) I add here in this last line a method to Load Page with data from item.