Catching Modifier-Keys in WPF ContextMenu - wpf

I would like to use the LeftAlt and RightAlt keys to alter MenuItems within an open ContextMenu. I want this all happen while the menu is already open - not while right mouse is clicked to open the context menu. I did the following:
ContextMenu.KeyDown += ContextMenu_KeyDown;
void ContextMenu_KeyDown(object sender, KeyEventArgs e)
{
if( e.Key == Key.LeftAlt || e.Key == Key.RightAlt )
{
e.Handled = true;
// DEMO
MenuItem firstItem = this.ContextMenu.Items[0] as MenuItem;
if( firstItem != null ) firstItem.Header = "Alt Pressed!";
}
}
Unfortunately this is not working. As soon as I press the Alt-Key the ContextMenu is closed although i use e.Handled = true;. Why is this? How can I catch the Alt-Keys and alter the context menu and leave the menu open?

According to this post (WPF: When Alt key is pressed, my ContextMenu won't open), it is a built-in behavior of the MenuBase class. You will need to choose another modifier key to accomplish this.
Here is the MSDN page explaining it : https://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.menubase.onkeydown.aspx

Related

WPF Datagrid Selection Issue

In my WPF application I have one datagrid and one textbox. In the textChanged event of the textbox, I put this:
myDatagrid.ItemsSource =
myListOfObjects.Where(item => item.Name.Contains(MyTextBox.Text)); //Filter
if (myDatagrid.Items.Count > 0) // If no itens, then do nothing
{
myDatagrid.SelectedIndex = 0; // If has at least one item, select the first
}
myDatagrid.Items.Refresh();
Note that I force the selection when the text changes, in the first row of the DataGrid.
But unfortunately, the color of the row does not change to blue, making it hard to see the selection.
I realy need this, because in the PreviewKeyDown event of the textbox I have this:
private void myTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
{
if (!(myDataGrid.SelectedIndex <= 0))
{
myDataGrid.SelectedIndex--; // Go one position Up
}
}
if (e.Key == Key.Down)
{
if (!(myDataGrid.SelectedIndex == myDataGrid.Items.Count - 1))
{
myDataGrid.SelectedIndex++; // Go one position Down
}
}
}
So, when the textbox is focused and the user press the Up or the Down key, the selection does not appear to change.
Any idea of how I can make the selected item on the datagrid change it's color to blue?
Other thing: in my virtual machine, it works!! With the same code! How it's possible?
I think that is the aeroglass, but I change the theme to the Windows 7 Basic (same in the virtual machine) and still don't work.
Thanks, and sorry for my english.
Could you try using SelectedItem? you could always create a new property and bind to this and then set this item directly rather than using the selected index. Hopefully this would trigger any additional logic in the DataGrid control :)
//Declare property outside of method
public ObjectType SelectedItem { get; set; }
//Set datacontext on load
DataContext = this;
myDatagrid.ItemsSource = myListOfObjects.Where(item => item.Name.Contains(MyTextBox.Text)); //Filter
if (myDatagrid.Items.Count > 0) // If no itens, then do nothing
{
SelectedItem = myDatagrid.ItemSource[0]; // If has at least one item, select the first
}
myDatagrid.Items.Refresh();
Also don't forget to set your binding!
SelectedItem="{Binding SelectedItem}"
hope that helps!

WPF Datagrid drag and drop questions

I have a WPF Datagrid and I'm implementing drag and drop functionality.
The datagrid has a list of "files" and the user can drag them and copy the file to the desktop.
This is done like this:
string[] files = new String[myDataGrid.SelectedItems.Count];
int ix = 0;
foreach (object nextSel in myDataGrid.SelectedItems)
{
files[ix] = ((Song)nextSel).FileLocation;
++ix;
}
string dataFormat = DataFormats.FileDrop;
DataObject dataObject = new DataObject(dataFormat, files);
DragDrop.DoDragDrop(this.myDataGrid, dataObject, DragDropEffects.Copy);
I have two questions:
1. When I want to drag multiple items- this is a problem because after I select a couple and start clicking on one to start dragging- only that gets selected and the other items get deselected. I tried the solution that is given here but for some reason it doesn't work.
2. I want to remove the dragged item from the datagrid after it is copied. The problem is that I don't know how to check if the file was copied or whether the user just dragged it on the screen without copying it.
I hope you can help me solve these problems.
Thanks!
I think this i what you are looking for:
add this code to the DataGrid__PreviewMouseLeftButtonDown event handler:
private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.startingPosition = e.GetPosition(null);
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree until get a row or null
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
//if this is a row (item)
if (dep is DataGridRow)
{
//if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
if (songListDB.SelectedItems.Contains((dep as DataGridRow).Item))
{
// now the drag will drag all selected files
e.Handled = true;
}
}
}
and now the draging won't change you selection.
Have a good luck!
I used that article to write my answer
Improved on finding the row.
Also selecting the clicked row when not dragging is added.
This now behaves exactly as other Microsoft selectors (eg Outlook)
public TreeDataGrid()
{
Loaded += TreeDataGrid_Loaded;
LoadingRow += new EventHandler<DataGridRowEventArgs>(TreeDataGrid_LoadingRow);
}
#region MultiSelect Drag
object toSelectItemOnMouseLeftButtonUp;
void TreeDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonDown);
e.Row.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonUp);
}
void Row_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
toSelectItemOnMouseLeftButtonUp = null; // always clear selecteditem
if (SelectedItems.Contains(row.Item)) //if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
{
e.Handled = true; // this prevents the multiselection from disappearing, BUT datagridcell still gets the event and sets DataGrid's private member _selectionAnchor
toSelectItemOnMouseLeftButtonUp = row.Item; // store our item to select on MouseLeftButtonUp
}
}
void Row_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
if (row.Item == toSelectItemOnMouseLeftButtonUp) // check if it's set and concerning the same row
{
if (SelectedItem == toSelectItemOnMouseLeftButtonUp) SelectedItem = null; // if the item is already selected whe need to trigger a change
SelectedItem = toSelectItemOnMouseLeftButtonUp; // this will clear the multi selection, and only select the item we pressed down on
typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, new DataGridCellInfo(row.Item, ColumnFromDisplayIndex(0))); // we need to set this anchor for when we select by pressing shift key
toSelectItemOnMouseLeftButtonUp = null; // handled
}
}
#endregion

GridView loses SelectedIndex value when ItemsSource is refreshed

Microsoft I think this may be a bug. Have a ListView GridView to display a single record.
Naturally the down arrow key navigates through the ListViewItems. That is the behavior I expect. In XAML the ItemsSource and SelectedIndex is bound. The behavior I want is the right and left arrow keys to navigate to the next and prior record.
The way I achieved this is to handle ListView PreviewKeyDown Event. The problem I had is the SelectedIndex is reset to -1 when the ItemSource is refreshed and I want it to stay on the old SelectedIndex. So I had to manually reset the SelectedIndex as shown below.
Here is my problem: After AND ONLY DIRECTLY AFTER a left arrow or right arrow key the up and down keys do not pass the correct value for SelectedIndex.
For example SelectedIndex = 4 then right arrow and then down key the value passed to SelectedIndex is 0 and the value passed should be 4. The ListView is visually on SelectedIndex 4 so it is like it knows the SelectedIndex is 4 but it also does not know. If I do not change the ItemsSource the up and down arrow keys work correctly. I tried KeyDown and KeyUp events but in the case those events just don't fire at all in the fail condition described above.
WPF 4.0 Visual Studio 2010.
private void lvCurDocFields_PreviewKeyDown(object sender, KeyEventArgs e)
{
Debug.WriteLine("lvCurDocFields_PreviewKeyDown " + e.Key.ToString());
e.Handled = false;
Int32 lastIndex;
switch (e.Key) // e.KeyCode
{
case Key.Right:
lastIndex = lvCurDocFields.SelectedIndex;
App.StaticGabeLib.Search.SelectedDocIndex++;
if (lvCurDocFields.SelectedIndex != lastIndex)
{
lvCurDocFields.SelectedIndex = lastIndex;
}
e.Handled = true;
break;
case Key.Left:
lastIndex = lvCurDocFields.SelectedIndex;
App.StaticGabeLib.Search.SelectedDocIndex--;
if (lvCurDocFields.SelectedIndex != lastIndex)
{
lvCurDocFields.SelectedIndex = lastIndex;
}
e.Handled = true;
break;
}
base.OnPreviewKeyDown(e);
}
Normally, I store a reference to the item that was selected, update the list, and re-select it afterwards. ListIndex isn't a reliable way to maintain a selection if things are inserted or deleted from the list.
if(MyListControl.Items.Contains(PreviouslySelectedItem)) MyListControl.SelectedItem = PreviouslySelectedItem;

WPF DataGrid - How to automatically exit Edit Mode?

I have implemented WPF DataGrid Single-Click Editing from Codeplex.
In that solution, the clicked cell is focused and the row is selected to achieve
single-click editing of DataGrid. It worked great.
Here's the code:
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
But I also want my DataGrid to automatically exit editing mode (without hitting Enter key)
when a cell value is changed. For example, I have a combobox in the cell when in edit mode. When user selects a value in combobox, it will automatically databind the selected value. But then the user still need to click Enter to exit edit mode. How can I exit edit mode automatically?
I've tried listening for property changes and call CommitEdit function of DataGrid to exit edit mode automatically. Works great and here's the code:
void _gameCompareViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "End Edit")
{
AlignGrid.CommitEdit();
}
}
But now the Single-Click editing feature will not work for the current cell.
I have to click a different row first in order for it to work.
I think what I want is when CommmitEdit is called, it automatically selects a
different row. (Like when you hit Enter, it will go to the next row)
Any suggestions guys? Please show me codes on how to do this. Im running out of time here for my project.
Thanks for the help.
to flip from cell editing template back to cell template:
dataGrid.CancelEdit();

WPF DataGrid switch template between view mode and edit mode

If have a WPF DataGrid on the left of a Window with an area to the right for displaying the selected record. The selected record consists of Textboxes and ComboBoxes that are disabled until the edit button is clicked. All works as expected.
However, it seems a bit clumsy to be populating ComboBoxes when the SelectedItem of the DataGrid being changed. A much lighter control such as a TextBlock could be used until the Edit button is clicked, then the TextBlocks could be switched out for ComboBoxes.
I'm sure this can be done with some sort of templating but when I tried to experiment with this, all of the events that are associated with the ComboBoxes report an error as they're no longer present as they have been replace with TextBlocks in "View mode".
I'm probably going about this wrong so some guidance would be appreciated.
here is excelent article
To apply single-click editing to all cells in the DataGrid
Paste the style below into the Resources of your DataGrid
Paste the method into the code behind
To apply single-click editing to only certain cells in the DataGrid
Set an x:Key on the Style (ex. )
Paste the style into the Resources of your DataGrid
Apply the style to the CellStyle property of the columns which you'd like to have single click editing (ex. )
Paste the method into the code behind
//
// SINGLE CLICK EDITING
//
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
static T FindVisualParent<T>(UIElement element) where T : UIElement
{
UIElement parent = element;
while (parent != null)
{
T correctlyTyped = parent as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
The ContentTemplateSelector property should allow you to select one template or another depending on the current mode (view/edit)
The marked answer link is dead.
This may help instead:
http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing

Resources