Get the item doubleclick event of listview - c#

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.

Related

How to determine the row number of a listview when the user clicks with the mouse on an object? WPF [duplicate]

Bound column in a ListView GridView
How to get the DataSource in a MouseDown event
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"
MouseDown="NameCol_mousedown"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
This works in another project with a button in a ListView.
This is what it tried ...
Error Unable to cast object of type 'MS.Internal.NamedObject' to type 'ListViewDragDrop.DocProp'.
The DataSource is DocProp.
private void NameCol_mousedown(object sender, MouseButtonEventArgs e)
{
TextBlock tb = (TextBlock)sender;
object data = tb.DataContext;
dataSource = (DocProp)tb.DataContext;
}
try this...
private void NameCol_mousedown(object sender, MouseButtonEventArgs e)
{
var tb = (TextBlock)e.OriginalSource;
var dataCxtx = tb.DataContext;
var dataSource = (DocProp)dataCxtx;
}
For anyone still having problems, this works fine as well.
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var baseobj = sender as FrameworkElement;
var myObject = baseobj.DataContext as (Object you expect);
// Example: var myObject = baseobj.DataContext as Dog;
// myObject.Bark();
}

Select all check boxes WPF

I want to make all check boxes selected by selecting check box names with "All of Above".
the checkboxes are in a List box
<ListBox SelectionMode="Multiple"
BorderThickness="0"
ItemsSource="{Binding QuestionThreeSelection}"
SelectedItem="{Binding QuestionThreeSelection}"
Name="listBoxList"
SelectionChanged="listBoxList_SelectionChanged">
<ListBox.InputBindings>
<KeyBinding Command="ApplicationCommands.SelectAll"
Modifiers="Ctrl"
Key="A" />
</ListBox.InputBindings>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Checked="CheckBox_Checked_1"
Content="{Binding SourceName}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
back Code
private void CheckBox_Checked_1(object sender, RoutedEventArgs e)
{
var oo = listBoxList;
CheckBox cb = (CheckBox)sender;
//var w=e;
IEnumerable<AddSource> listallityem = ((IEnumerable<AddSource>)listBoxList.Items.SourceCollection).Where(r => r.IsSelected == false);
//IEnumerable<AddSource> listallityem1 = ((IEnumerable<AddSource>)listBoxList.Items.SourceCollection);
AddSource vv = cb.DataContext as AddSource;
if ((bool) cb.IsChecked)
{
}
if (vv.SourceName== "All of the above")
{
r = listBoxList.ItemsSource;
foreach (AddSource item in wer)
{
item.IsSelected = true; // false in case of unselect
}
}
}
Can someone suggest a method?
You could handle the Checked and Unchecked event for your "All of Above" CheckBox something like this:
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
SelectAll(true);
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
SelectAll(false);
}
private void SelectAll(bool select)
{
var all = listBoxList.ItemsSource as IEnumerable<AddSource>;
if (all != null)
{
foreach (var source in all)
source.IsSelected = select;
}
}
Make sure that your AddSource class implements the INotifyPropertyChanged and raise the PropertyChanged event in the setter of the IsSelected property.

How to Get Tapped Item from Tapped Event in StackPanel

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;
}

TabChanged event of TabControl in WPF

I have a TabControl in WPF. I want to find an event that occurs when changing tabs. What is the name of this event?
The TabControl inherits from a Selector which contains the SelectionChanged event.
<TabControl SelectionChanged="OnSelectionChanged" ... />
private void OnSelectionChanged(Object sender, SelectionChangedEventArgs args)
{
var tc = sender as TabControl; //The sender is a type of TabControl...
if (tc != null)
{
var item = tc.SelectedItem;
//Do Stuff ...
}
}
I just want to add my point here. And I will use cool answer of #pratap k to do it.
<TabControl x:Name="MyTab" SelectionChanged="TabControl_SelectionChanged">
<TabItem x:Name="MyTabItem1" Header="One"/>
<TabItem x:Name="MyTabItem2" Header="2"/>
<TabItem x:Name="MyTabItem3" Header="Three"/>
</TabControl>
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MyTabItem1 !=null && MyTabItem1.IsSelected)
// do your staff
if (MyTabItem2 !=null && MyTabItem2.IsSelected)
// do your staff
if (MyTabItem3 !=null && MyTabItem3.IsSelected)
// do your staff
}
As you see the difference is to add checking for NULL.
That is it!
I didn't get the selected answer to work, maybe something has changed, maybe my setup is different.
My solutions is straightforward, you cast the sender to become the tabControle. Then you pull out the selected TabItem (selectedValue) and cast this to an TabItem.
In my situation, I need to know "who" changed, so I look for the name of the TabItem, to better react to a specific event.
XAML
<TabControl SelectionChanged="OnTabItemChanged">
<TabItem Name="MainTap" Header="Dashboard"></TabItem
</TabControl>
C#
private async void OnTabItemChanged(object sender, SelectionChangedEventArgs e)
{
TabControl tabControl = sender as TabControl; // e.Source could have been used instead of sender as well
TabItem item = tabControl.SelectedValue as TabItem;
if (item.Name == "MainTap")
{
Debug.WriteLine(item.Name);
}
}

How to select a row or a cell in WPF DataGrid programmatically?

In WinForm DataGridView, it automatically selects the first row when initialized. It drove me crazy when I tried to turn that feature off. Moving to WPF DataGrid, it seems Microsoft has decided to turn this feature off, which is a good thing I think. However, I have hard time to enable this feature now. For some DataGrid, I want the first row to be selected automatically after grid is populated through data binding. There are some suggestions in Internet, but I couldn't make that work. I hope for better luck here.
Set IsSynchronizedWithCurrentItem = "true".
EDIT:
To address your comment, I assume that your DataGrid's SelectionUnit is set to "Cell", is it? Okay, I'm not sure if this is the best solution but one thing you can do is handle the Loaded event for the DataGrid and manually set the selected cell in the code-behind. So you'll have something like this:
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectedCellsChanged="dg_SelectedCellsChanged" SelectionUnit="Cell"
Loaded="dg_Loaded">
...
</DataGrid>
Event-Handler:
private void dg_Loaded(object sender, RoutedEventArgs e)
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
Note that this will only work if the DataGrid.SelectionUnit is set to "Cell". Otherwise, I believe it will throw an exception.
EDIT2:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Click="Button_Click">Reset</Button>
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
DataContextChanged="dg_DataContextChanged"
ItemsSource="{Binding Items}"
Loaded="dg_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Window>
Code-Behind:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.LoadItems();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.LoadItems();
}
private void LoadItems()
{
this.DataContext = new { Items = new List<string> { "Item1", "Item2", "Item3" } };
this.SelectFirstItem();
}
private void dg_Loaded(object sender, RoutedEventArgs e)
{
SelectFirstItem();
}
void SelectFirstItem()
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
private void dg_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.SelectFirstItem();
}
}
}
You can do this consistently in the DataGrid.Loaded event. Just obtain the first row and have the row fire the selection event.
void MyGridLoaded(...) {
DataGridRow r = yourGrid.ItemContainergenerator.ContainerFromIndex(0) as DataGridRow;
if(r != null) {
r.IsSelected = false;
r.IsSelected = true;
}
}
I'm not sure this is a bug because you may not be guaranteed to have selection events fire from your object until the control is loaded. Don't know.
You could try this.
this.dataGrid.SelectionMode = DataGridSelectionMode.Single;
// Selects the 4th row.
this.dataGrid.SelectedIndex = 3;
I'm glad to report I found a solution for this problem through ItemContainerGenerator.StatusChanged event.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (dataGrid.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
dataGrid.SelectedIndex = 0;
}
}
It looks when this event is fired with status ContainersGenerated, dataGrid is fully initialized. To me, this is more like DataGridView's DataBindingComplete event in WinForm. If so, the "DataContextChanged" event should really be called "DataContextChanging" event.
This was inspired by a post here I accidently found while looking for another clue.

Categories

Resources