Controls with ContextMenuStrip - winforms

I am using VS2012, C#, Winforms.
My application generates about 100 label controls at runtime. I want the user to right-click on a label control, bring up a context menu strip. I have this part working. But I am having trouble determining which control is being clicked on when I try to respond to a the context menu item click event. How can I pass on the control to the menu item click event?
I am using this code to determine the source control but it always causes a null exception:
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
Control sourceControl = new Control();
sourceControl = contextMenuStrip1.SourceControl;
MessageBox.Show(sourceControl.Text);
}
sourceControl always get a null from contextMenuStrip1.SourceControl;

The SourceControl property can be null, as this property is best used during the opening event. There are a couple of workarounds available. Check these two out on StackOverflow:
ContextMenuStrip.Owner Property null When Retrieving From Nested ToolStripMenuItem
Get the SourceControl of my ContextMenuStrip when I use the shortcut key

Related

Show ContextMenu for TreeViewItem by raising events in code

I want to write a coded UI test for my treeview with context menu. The idea is to validate if the context menu is added to treeViewItem.
So far I tried to raise PreviewMouseRightButtonUp event. This is not working.
If I subscribe to the event then I get a callback after right-clicking the tree item. But raising the event manual does not cause the context menu to be added.
Here is how I am raising the event:
MouseButtonEventArgs eventArgs = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right);
eventArgs.RoutedEvent = Mouse.MouseUpEvent;
uiElement.RaiseEvent(eventArgs);
If you want to validate if the context menu is added to treeViewItem, why not right-click on the tree item and look for the existence of a menu in the window.

Prevent control loosing focus when child gets focus

Ok so I have an issue where I have been trying to create a custom control in Silverlight. It is simply a button that when pressed opens a dropdown menu, however the dropdown menu is a child control. I have a property (isDropDownOpen) that controls whether the dropdown is open. I want that when the control loses focus that the property goes to false so implemented the following override in my class.
protected override void OnLostFocus(System.Windows.RoutedEventArgs e)
{
base.OnLostFocus(e);
Object focusedElement = FocusManager.GetFocusedElement();
FrameworkElement element = focusedElement as FrameworkElement;
if (element != null)
{
IsDropDownOpen = false;
}
}
The problem is that the control looses focus when the child control gains focus so the menu closes as soon as I click on anything other than the button. I can’t really see how to work around this, any ideas?
EDIT: Essentially what I wish to do is check if the item is a child before actually changing the property. In wpf I would do something using 'IsChild()' or '.containsFocus()' however these do not appear to e available in silverlight...
Using silverlight 5.0.
I found the following link to be a solution to my issue.
http://icircusmonkey.wordpress.com/2012/08/26/silverlight-how-to-close-the-popup-when-user-clicks-outside-of-the-control/
The solution in my case was to find the ancestor of the control (going up to the window) and subscribing an event handler to close the menu when a click is registered on the window/ancestor. Works perfectly.

Setting Default Keyboard Focus On Loading A UserControl

I have an MVVM setup with a mainwindow that contains a ContentControl.
I set this to a particular viewmodel which then maps to a view.
A view is a usercontrol.
I want to be able to set the default keyboard focus to a default element in the usercontrol(View) when it loads so the application can eventually be driven just by using up, down, left, right and enter.
Some of my failed attempts are setting
FocusManager.FocusedElement="{Binding ElementName=DefaultElement}"
in my content control tag. This sets the logical focus but not the keyboard focus
I'd rather keep the solution in xaml if possable but have tried placing the following in code behind.
Keyboard.Focus(DefaultElement);
This does not work but if I popup a message box first it does. I'm a little confused as to why.
MessageBox.Show(Keyboard.FocusedElement.ToString());
Keyboard.Focus(DefaultElement);
EDIT::::
I just placed this in my onloaded event of my user control. It seems to work but can anyone see any issues that might arrise at this priority level. I.E a circumstance when the action will never run?
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
Keyboard.Focus(DefaultElement);
}));
It seems that this wpf the you have to implement a workaround on a case by case basis. The solution that seemed to work best, most of the time for me was to insert the focus code inside the dispatcher when OnVisible was changed. This sets the focus not only when the View/Usercontrol loads but also if you a changing Views by way of Visibility. If you Hide and then Show a ContentControl that is mapped to your ViewModels then the Loaded event won't fire and you'll be forced to Mouse input, or tabbing (Not so good if you want to navigate your app with a remote control).
VisibilityChanged will always fire however. This is what I ended up with for my listbox.
private void ItemsFlowListBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
ItemsFlowListBox.Focus();
ItemsFlowListBox.ScrollIntoView(ItemsFlowListBox.SelectedItem);
}));
}
}
I had the same symptom for a WPF UserControl hosted in a Winforms application. Just wanted to note I was about to try this solution when I found a normal TabIndex in the Winforms app fixed it
Per How to set which control gets the focus on application start
"The one with the minimum tab index automatically gets the focus
(assuming the TabStop property is set to true). Just set the tab
indices appropriately."
It's a tricky one with no easy answer. I'm currently doing this, although I'm not sure I like it:
public MyView()
{
InitializeComponent();
// When DataContext changes hook the txtName.TextChanged event so we can give it initial focus
DataContextChanged +=
(sender, args) =>
{
txtName.TextChanged += OnTxtNameOnTextChanged;
};
}
private void OnTxtNameOnTextChanged(object o, TextChangedEventArgs eventArgs)
{
// Setting focus will select all text in the TextBox due to the global class handler on TextBox
txtName.Focus();
// Now unhook the event handler, since it's no longer required
txtName.TextChanged -= OnTxtNameOnTextChanged;
}
And in case you're wondering what the global class handler does, it's this:
protected override void OnStartup(StartupEventArgs e)
{
...
// Register a global handler for this app-domain to select all text in a textBox when
// the textBox receives keyboard focus.
EventManager.RegisterClassHandler(
typeof (TextBox), UIElement.GotKeyboardFocusEvent,
new RoutedEventHandler((sender, args) => ((TextBox) sender).SelectAll()));
which auto selects TextBox text when receiving keyboard focus.

using routed events within Silverlight user controls

within my current project file I have a user control that has a storyboard animation applied to the control. When a button is clicked in the page the storyboard starts and basically visually presents the control to the user. The storyboard resides in the current page as a resource
<navigation:Page.Resources>
<Storyboard x:Name="PreferncesOpen">....</Storyboard x:Name="PreferncesOpen">
</navigation:Page.Resources>
Within the page I have button that I have a click event on that starts the storyboard
private void btnOpenPreferences_Click(object sender, RoutedEventArgs e)
{
preferencesPanel.Visibility = System.Windows.Visibility.Visible;
PreferncesOpen.Begin();
}
Within the userControl (preferencesPanel) I have a button that when clicked needs to close/collapse the user control. I plan to do this using Visibility.collapsed. I assume that I need to use routed commands since the button is within the user control but the actions need to be called within the page that contains the control? I'm still new to routed commands and I assume this is the correct approach. I'm just unsure how to click on a button within the user control and have it modify or execute commands that would impact how the page (in which this control resides) may change or for that part affect other elements within the page? For example when the button is clicked within the user control I would like the visibility of the user control to be set to collapsed. I also would like to have the width of one of the grid columns within the main page re-size. I have done this in the past using the code behind for the page but I am trying to separate some of this and I thought routed commands would be the way to go?
I'd greatly appreciate any tips.
Thank you in advance
The title is a bit misleading, you're asking about commands rather then routed events if I understand you correctly.
Here's an example of using a DelegateCommand<T> from the Prism library; It happens to be my personal preference.
Markup :
<Button x:Name="MyButton" Content="Btn" Command="{Binding DoSomethingCommand}"/>
Code-behind* or ViewModel :
(* if you're not using MVVM make sure to add MyButton.DataContext = this; so you're sure that the button can databind to your code behind effectively)
public DelegateCommand<object> DoSomethingCommand
{
get
{
if(mDoSomethingCommand == null)
mDoSomethingCommand = new DelegateCommand(DoSomething, canDoSomething);
return mDoSomethingCommand;
}
private DelegateCommand<object> mDoSomethingCommand;
// here's where the command is actually executed
void DoSomething(object o)
{}
// here's where the check is made whether the command can actually be executed
// insert your own condition here
bool canDoSomething(object o)
{ return true; }
// here's how you can force the command to check whether it can be executed
// typically a reaction for a PropertyChanged event or whatever you like
DoSomethingCommand.RaiseCanExecuteChanged();
The argument that's passed to the above function is the CommandParameter dependency property (in Prism it's an attached property as well as the Command property if memory serves me right).
When it's set, you can pass a value of your choosing to the command that you wish to execute.
Hope that helps.

WPF combobox-like custom control

I would like to create custom control that will look like standard WPF ComboBox, but instead of instead of having an ItemsPresenter in the popup there will be another custom control. So, I created a new class that derives from System.Windows.Controls.Control, added a IsDropDownOpen property and created a style that is actually a copy of default ComboBox style (main idea is that the Popup.IsOpen and ToggleButton.IsPressed properties are bound to the IsDropDownOpen property of the control).
The problem is that the Popup is not closed when I click outside of the control.
I took a look at the ComboBox class in the Reflector and found out that ComboBox used some logic to update the IsDropDownOpen property when it loses mouse capture. But that code uses some internal classes. Is there any alternative way to determine if the user clicked outside of the control and close the Popup?
UPD: I didn't find the way to attach a file to post, so I uploaded sample project here
There is a custom control that looks like ComboBox, but it has a TreeView in a popup. When you open popup and click outside of the control it closes automatically, but if you open popup, expand 'Item2' and then click outside the popup isn't closed. The question is how to fix this?
There is the Control.LostFocus event, maybe handling that would be sufficient for this.
This code solves the problem.
In the static contructor:
EventManager.RegisterClassHandler(typeof(CustomComboBox), Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnMouseCaptureLost));
Event handler implementation:
private void OnMouseCaptureLost(object sender, MouseEventArgs e)
{
if (Mouse.Captured != _container)
{
if (e.OriginalSource != _container)
{
Mouse.Capture(_container, CaptureMode.SubTree);
e.Handled = true;
}
}
}

Resources