Is there a way to get OnItemRightTapped event on ListView or GridView that works exactly like ItemClick, except obviously react only on right tap?
You can add an event handler for mouse down and then determine the click source in the code:
private void listView_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
{
// Do what u need to do here
}
else
e.Handled = true;
}
I have a DataGridView where SelectionMode=FullRowSelect and MultiSelect=False.
When a user clicks on a row it is selected as expected. However, clicking on the same row again does not deselect the row.
How can the row selection be made to toggle between selected and unselected?
As far as I know there is no out of the box functionality that will do this.
I managed to get the effect you are asking for with the following code:
public partial class Form1 : Form
{
private bool selectionChanged;
public Form1()
{
InitializeComponent();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (!selectionChanged)
{
dataGridView1.ClearSelection();
selectionChanged = true;
}
else
{
selectionChanged = false;
}
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
selectionChanged = true;
}
}
That uses the dataGridView's SelectionChanged and CellClick events, along with a class level variable holding the state of the selection.
How can focus the controls when select a tabitem in a tabcontrol?
You should capture the Selection changed event of the TabControl and inside that you focus the control you need. Just as
private void TabControl1_SelectionChanged(object sender, EventArgs e)
{
control1.Focus();
}
Not sure I understand what you're asking completely, but you probably want to capture the SelectionChanged event for the TabControl:
public Window1()
{
InitializeComponent();
TabControl1.SelectionChanged += TabControl1_SelectionChanged;
}
private void TabControl1_SelectionChanged(object sender, EventArgs e)
{
TabItem item = (TabItem)TabControl1.SelectedItem;
// Find the first control in the TabItem content and focus it?
}
I've got a rather funny problem with WPF. I have a tree-view, and selecting items works fine so far. The problem is, I want to unselect the currently selected item when the user clicks inside the blank area of the treeview. By default, the treeview keeps the current item selected, and I have added a context-menu option to deselect it, which is rather hardcore:
// Note: This is done recursivly from the start, so it
// works for child items as well
treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem) as TreeViewItem).IsSelected = false;
Moreover, this is counter-intuitive, as it requires the user to right-click first, and second, after deselecting it with this way, the user cannot select it any more by clicking on the item. How is this supposed to work?
Edit: Some more information: I've added a handler to the TreeView to handle mouse click events, but the sender is always a TreeView instance, even if I click directly on a TreeViewItem. If I add a handler to my TreeView.ItemTemplate instead (i.e. the first child in the template), I never get events when I click on the empty area (which is rather logical). The code looks like this:
private void MyTreeView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ((sender as TreeViewItem) == null)
{
// Always triggered
System.Diagnostics.Trace.Write("Empty area clicked");
}
}
And the XAML for this is:
<TreeView x:Name="MyTreeView" Margin="3" MouseUp="MyTreeView_MouseUp">
I found this to work much better for me. I check the originalsource which for me if it comes form a treeviewitem will be an image or a textblock. I also use a view object with a HierarchicalDataTemplate and the BasicTreeViewBase is the base class for all of my different objects. Here is the code.
private void TemplateTreeView_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right && !(e.OriginalSource is Image) && !(e.OriginalSource is TextBlock))
{
BasicTreeViewBase item = TemplateTreeView.SelectedItem as BasicTreeViewBase;
if (item != null)
{
TemplateTreeView.Focus();
item.IsSelected = false;
}
}
}
The un-selectable problem can be solved with a call to Focus on the TreeView after setting TreeViewItem.IsSelected.
There can be two more problem :
The treeview is binded so the SelectedItem is an item of the binded collection.
There is many levels so ItemContainerGenerator do not contain deepest level objects
for all this reason i use this function, but the selection must not fire any events.
private void UnselectTreeViewItem(TreeView pTreeView)
{
if(pTreeView.SelectedItem == null)
return;
if(pTreeView.SelectedItem is TreeViewItem)
{
(pTreeView.SelectedItem as TreeViewItem).IsSelected = false;
}
else
{
TreeViewItem item = pTreeView.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem;
if (item != null)
{
item.IsSelected = true;
item.IsSelected = false;
}
}
}
I implemented a general selection control once, and required this behaviour.
This is how my method looked (adapted for treeview):
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
DependencyObject dpSource = e.OriginalSource as DependencyObject;
if (dpSource.FindVisualAncestor(o => typeof(TreeViewItem).IsAssignableFrom(o.GetType())) == null)
UnselectAll();
}
Basically, walk up the tree from the source. If a TreeViewItem was not found, than the user clicked empty space.
Use the extension class below
public static class TreeViewExtensions
{
public static TreeViewItem ContainerFromItem(this TreeView treeView, object item)
{
TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
else
return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item);
}
private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item);
if (recursionResult != null)
return recursionResult;
}
return null;
}
}
Then in MouseDown event of treeview use the extension method as below:
private void trview_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ((sender as TreeViewItem) == null)
{
if (this.trview.ContainerFromItem(trview.SelectedItem) != null)
{
this.trview.ContainerFromItem(trview.SelectedItem).IsSelected = false;
}
}
this.trview.Focus();
}
Hope it works for you. I have it working in this way...
I was running into this situation myself with a custom Tree List View implementation after looking for a long time I finally found a solution that worked for me.
The full explanation can be found at http://social.msdn.microsoft.com/Forums/vstudio/en-US/36aca7f7-0b47-488b-8e16-840b86addfa3/getting-treeviewitem-for-the-selected-item-in-a-treeview
The basic idea is you capture the TreeViewItem.Selected event and save the source of the event into the Tag attribute on your TreeView. Then when you need to clear it, you can access the Tag attribute on your control and set the IsSelected value to False. This works for me with 2 levels of nested children. Hopefully it will work for you.
For persistence sake:
TreeView declaration
<TreeView Name="myTreeView" TreeViewItem.Selected="OnItemSelected"
ItemsSource="{Binding Source={StaticResource myHierarchicalData}}"/>
Event Handler
private void OnItemSelected(object sender, RoutedEventArgs e)
{
myTreeView.Tag = e.OriginalSource;
}
Clear selection logic
if (myTreeView.SelectedItem != null)
{
TreeViewItem selectedTVI = myTreeView.Tag as TreeViewItem;
// add your code here mine was selectedTVI.IsSelected = false;
}
This will deselect the currently selected TreeViewItem if none were clicked:
private void MyTreeView_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
if ((sender as TreeViewItem) == null) {
TreeViewItem item = MyTreeView.SelectedItem as TreeViewItem;
if(item != null){
item.IsSelected = false;
}
}
}
Hope this is what you were looking for!
MVVM: Call this method in the eventhandler righ/left mouse click:
private void SetTreeViewSelection(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var treeView = (TreeView)sender;
if (treeView.SelectedItem == null)
{
return;
}
IInputElement dropNode = treeView.InputHitTest(mouseButtonEventArgs.GetPosition(treeView));
if (dropNode is ScrollViewer)
{
var myBindableObject = (MyBindableObject)treeView.SelectedItem;
myBindableObject.IsSelected = false;
}
}
For a C# treeview you use treeview.SelectedNode = null; I'm not sure if this works for WPF.
I'm new to WPF.
I have like 15 grids on my Window and I have a small menu on which I can click and choose which grid to show up or hide. One grid at a time only. I would like that grid to hode (fade out) when I hit Esc. I have all the animations already, I just need to know what grid is visible (active) at the moment.
I don't know how to get current topmost control of my Window.
My solution is when KeyDown event is triggered on my Window to:
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Escape)
{
//check all grids for IsVisible and on the one that is true make
BeginStoryboard((Storyboard)this.FindResource("theVisibleOne_Hide"));
}
}
By active, I assume that means the one that has keyboard focus. If so, the following will return the control that currently has keyboard input focus:
System.Windows.Input.Keyboard.FocusedElement
You could use it like this:
if (e.Key == System.Windows.Input.Key.Escape)
{
//check all grids for IsVisible and on the one that is true make
var selected = Keyboard.FocusedElement as Grid;
if (selected == null) return;
selected.BeginStoryboard((Storyboard)this.FindResource("HideGrid"));
}
An approach that would be more decoupled would be to create a static attached dependency property. It could be used like this (untested):
<Grid local:Extensions.HideOnEscape="True" .... />
A very rough implementation would look like:
public class Extensions
{
public static readonly DependencyProperty HideOnEscapeProperty =
DependencyProperty.RegisterAttached(
"HideOnEscape",
typeof(bool),
typeof(Extensions),
new UIPropertyMetadata(false, HideOnExtensions_Set));
public static void SetHideOnEscape(DependencyObject obj, bool value)
{
obj.SetValue(HideOnEscapeProperty, value);
}
public static bool GetHideOnEscape(DependencyObject obj)
{
return (bool)obj.GetValue(HideOnEscapeProperty);
}
private static void HideOnExtensions_Set(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var grid = d as Grid;
if (grid != null)
{
grid.KeyUp += Grid_KeyUp;
}
}
private static void Grid_KeyUp(object sender, KeyEventArgs e)
{
// Check for escape key...
var grid = sender as Grid;
// Build animation in code, or assume a resource exists (grid.FindResource())
// Apply animation to grid
}
}
This would remove the need to have code in codebehind.