WPF: Context Menu dissapears after item update in my GridView - wpf

so, I have this ListView in grid mode. I am dynamically updating it using a CollectionView. now, the problem I have is that when I open a context menu by right clicking on an item in my grid the context menu closes after the item updates--now, it is not a new item but it is the same item. Does anyone have any ideas on how I can make the contet menu stay open after the item updates?
[Edit]
The grid is part of a public safety application that updates in near real-time. so the items are periodically added, removed, and updated. If we right-click on an item to open the context menu and an update occurs before I can close it--even if the particular item does not change in any way--the context menu closes. The desired behavior is for the context menu to remain open.

If you could supply your XAML that would help, but my guess is that you have defined the context menu on the ListViewItem element and that the menu closes because the whole ListViewItem is regenerated or replaced by WPF.
Perhaps you can define the context menu on the ListView instead? You will have to update your commands and get the selected item from the list when executing, since the context will no longer be a specific item.

Related

Placement of context menu on devex grid control

I am using a devexpress grid control to display a grid. The grid shows a context menu. When i right click on a row, the menu is shown but only when the row is a newly added row. It means the menu is visible only on some rows so i have bound its visibility with a property on view model. The problem is if i right click on a row which doesn't show a context menu and then right click on the row which shows the context menu, the menu becomes visible on the last clicked row(the one which doesn't show context). Any help with this?

How to add a specific item as the last item of listview

I have a ListView control which is bound to a ObservableCollection, I want to add a specific button at the end of the last item, so that when user click the button, clear up the colltions, then hide the button. Also, if the collection is empty, don't like the button display. After searching, I found many solutions on how to change the last item's style, but in my scenario, the button isn't the element of the ItemsSource. Anyone can help?
Thanks
Add the button to the template so it appears on every element in the ListView. Then use a trigger to show/hide the button based on whether the item is the last item in the list.
One way to do this is to expose the last item in your list via a property on your ViewModel. The trigger should compare the DataContext of the template, which is the current item, against the LastItem. Success should set the visibility of the button.
I hope this helps.

Implementation of menu buttons in WPF/MVVM/Prism

I have a Region in the top left of the WPF application which I want to be my global button bar where the user chooses which screen they want to view, and the appropriate content will then be displayed in the main region. THere will also be a sub navigation region in the top right with sub-menu options within that screen, eg if the user clicked "Maintenance" from the main menu, the sub menu would show options for New, Update, Delete, Edit etc.
What I want to have is a way to create a custom menu bar by simply specifying a list of Text button names, and ICommand/Parameter pairs for the action to invoke on button click. The natural way to do this would be have a MenuButtonViewModel class with dependency properties Title, Command and CommandParameter. One more would also be needed, IsSelected, so there is some visual way for the user to see which screen you are currently on, so it needs to behave like a toggle button, but where only one button in the group can be selected at a time. I can then have a UserControl where the content of the bar binds to an ObservableCollection and uses data templates to render the button bar.
I have tried a few ways of doing this so far but cannot figure out a way that gives me the visual behaviour I want. These are my requirements
1) Button to change background to a different Brush OnMouseOver
2) When button is selected, a different Brush is displayed as the background until a new button in the group is selected, like a togglebutton IsSelected behaviour
3) Only one button in the group can be selected at a time
The ways I have tried to do this so far are
1) Extending RadioButton with my own class, adding dependency properties for command and commandparameter. Setting all controls to have the same group Id. Data template to override display of radio button to make it look like a visual button with triggers for mouseover and isselected.
This works fine, except for one thing. Once you select a radio button in a group, there is no way to deselect all options in the radio button group. So if you navigate to "maintenance" and then click the sub menu for "Countries" for example, then you are displayed the country maintenance screen. If you then go to a different area of the app and select "Deal Entry" from the main menu, you are taken to the deal entry screen. If you then click "Maintenance", it displays the generic "maintenance" content and brings back the sub menu control for maintenance, where "Country" is selected in the radio button group, but this is undesirable. When you navigate back to Maintenance, it should deselect all sub menu options, display the generic maintenance landing page content and let you select a sub menu option before displaying that screens content. The first time you load Maintenance, nothing is selected, but once you have chosen an option, then there is no way to have nothing selected again when you reload the maintenance screen.
2) I then tried extending a ListBox, styling it with a horizontal stackpanel for the content, each listboxitem is a menubuttonViewModel. This allows me to only select a single option at a time and to clear the selection when you navigate away from the page. It also lets me change the background when you mouse over each listboxitem.
The bit I can't get working with the listbox is to have the background different on the IsSelected trigger. There seems to be some trigger on the default ListBoxItem template that overrides anything you specify in CSS so no matter what trigger I put on the listboxitem or menubuttonviewmodel style, the background simply does not change. I think I need to redefine the data and content template for listboxitem, but only have it apply for this listbox, so it can't be a global template change to all listboxitems - as I want to be able to use listboxes elsewhere in the app without inheriting this behaviour.
Can anyone give their thoughts on these two approaches and how to perhaps solve the issues I'm having to make one of them work in the way I want, particularly if you can advise how I can override the content/data template for the listboxitems in my style so they do not use the default triggers, and I can get the IsSelected trigger working for me?
If I understood correctly, you would want to clear the selection on the RadioButtons from the Sub-Menu each time you navigate back from another Main Menu option.
In order to solve this, you could have every Radio Button "unchecked" by manually setting the RadioButton´s IsChecked property value to false. A possible solution could be the following:
If you want to clear any checked option from the Sub-Menu everytime you navigate to a different section of the Main Menu, you could first notify to the Sub-Menu´s ViewModel by publishing an event using the EventAggregator after selecting and clicking a different MainMenu button, from the SelectionChangedEventHandler method of the Main Menu´s ViewModel.
Therefore, the Sub-Menu EventHandler of the published event would update each RadioButton´s IsChecked property value to false, which it could be accomplished by using a "Two-Way" Binding between each IsChecked property defined on the View, and each boolean "RadioButton1IsChecked" property implemented on the ViewModel.
I hope this helped you.

Displaying a WPF context menu after a D&D operation

Here is my problem; I want to display a context menu, with items created on the fly in the code behind, when a D&D operation has finished.
What I can't do is
Insert an item that will cancel cancel the drop operation, if selected
I can't find a way to keep the menu open when I click anywhere outside of the menu
How can I do these two things?
Displaying the context menu will not block the D&D operation from completing, so it won't wait until the user addresses the context menu. You would have to somehow save the D&D action (capture what is being dropped and hold on to it) and wait to complete the action until after the context menu has been addressed.
A context menu will automatically close when it loses focus. However there is a StaysOpen property that overrides this behavior. If you set StaysOpen to true, it will remain open until you explicitly close it (by settings IsOpen to false).

Have TreeView update its SelectedItem when programmatically changed

In WPF I have a TreeView control where a particular item can be selected either by the user selecting the item directly in the tree view or by clicking on a screen control. The tree view is displaying a list of elements that are being displayed on a user defined form, basically a form designer application.
Here is my problem. When the user clicks on a screen control it calls a method that returns the TreeViewItem that represents the element. It then sets the IsSelected property to true for this element. It correctly changes the visual indicator in the TreeView and it raised the SelectedItemChanged event in the TreeView. This is all good.
However, it appears that somewhere behind the scenes the TreeView still thinks the previous item is selected. Here is why I have come to this conclusion. If I select ElementA by clicking on it in the TreeView is it correctly selected. If I then select ElementB by clicking on the screen control and programmatically setting the IsSelected property for the ElementB TreeViewItem it appears to have selected it correctly. Now if I select ElementA again by clicking on it in the TreeView it does nothing. The SelectedItemChanged event is not raised and the reverse selection box that indicates the selected item stays on ElementB. If I click on ElementB in the TreeView it also does not raise the SelectedItemChanged event, however it does not appear to update the internal flag since if I then click on ElementA on the TreeView it processes it correctly and raises the event.
The only workaround that I have found for this is in the SelectedItemChanged event handler to call the Focus method for the now selected TreeViewItem. If I do this I get the expected behaviour when I select screen controls and programmatically change the selected TreeViewItem.
This is not an acceptable solution though as it creates focus change flicker. When I select items on my form window the focus goes to the TreeView control and then back to the form, causing flicker and slight delay.
Anyone have any indeas.
Update
As requested here is some code. Here is my method of my Explorer window which is the manager of the TreeView in question.
public bool SelectItemByName(String controlName)
{
bool fReturn = false;
TreeViewItem tviToSelect = FindItemByName(_tviMaster, controlName);
if (tviToSelect != null && _tviSelectedItem != tviToSelect)
{
tviToSelect.IsSelected = true;
// Make sure the selected item is visible in the TreeView by expanding all of the parent nodes
ExpandAllParents(tviToSelect);
tviToSelect.BringIntoView();
fReturn = true;
}
return fReturn;
}
Every element has a unique identifier that I use as a cross reference between different areas of the interface. When you click a screen control it uses its identifier to find the cooresponding TreeViewItem in the TreeView. Then this code sets it as selected.
Then in my SelectedItemChanged event handler I had to include the following line.
_tviSelectedItem.Focus();
This fixes my initial issue but introducing the unwant screen flicker.
To recap, I select ElementA in the TreeView directly, then select one or more other elements in the form designer which in turn calls SelectItemByName to programatically set the selected item. All visual indicators show that this worked. In the TreeView the highlighted item changes to the new item that is selected. After selecting any number of elements through the form designer interface if you select ElementA by clicking on it directly in the TreeView it does nothing. It does not get highlighted and it does not fire the SelectedItemChanged event. If you inspect the SelectedItem and SelectedValue properties of the TreeView they all correctly coorespond to the item that was programmatically selected. However, the control somewhere appears to think that ElementA is still selected and doesn't recognize that the selection is changing.
I cannot believe that other people haven't run into this. It appears to be a significant flaw in the TreeView contol in WPF. Not sure if WinForms has the same issue or not.
Each TreeViewItem has an IsSelected property, and I suspect the old one isn't getting set to false. Try setting it to false whenever you set the new item to true.
var currentItem = treeView.ItemContainerGenerator
.ContainerFromItem(treeView.SelectedItem) as TreeViewItem;
currentItem.IsSelected = false;
If that doesn't work, try setting focus on the newly selected item at the same time as when you select it. Don't forget that WPF also has two focus scopes: Logical Focus and Keyboard Focus. You may need to set both.
treeViewItem.Focus(); // Sets Logical Focus
Keyboard.Focus(treeViewItem); // Sets Keyboard Focus

Resources