Find Focus To Know What To Copy - c#

I have a Copy button in my Ribbon and I need to determine what control is focused so I know which Copy method to invoke. Any ideas on how to do this? I was thinking FocusManager.GetFocusedElement but I am using MVVM so I don't know what to pass as an argument.
private void Copy()
{
if (**Here_I_need_to_know_what_is_focused** is DataGridCell)
{
ApplicationCommands.Copy.Execute(null, this.DisplayedData);
}
else if ((this.CurrentFiles.SelectedItem is DSViewModel) || (this.CurrentFiles.SelectedItem is QViewModel))
{
this.CurrentFiles.Copy(this.CurrentFiles.SelectedItem);
}
else
{
ApplicationCommands.Copy.Execute(null, Keyboard.FocusedElement);
}
}

It really depends where your code is located.
I assume that it is located in the view model - in this case you will not have access to the FocusMangager directly. In order to get the currently focused element, you will have to pass it to the function via the CommandParameter attribute. This can be done by binding if there is only one possible target object.
However, I can imagine that this might be not an option, as the copy button in your ribbon most likely handles several objects. In this case I would not use the Command and CommandParameter attributes, but implement a click handler in the code behind.
Here, you now got the option to determine the focussed element or other target object using all the view's functionality, including the FocusManager. After you have determined the target you now can call you command's Execute method passing the correct object as a parameter.
Before trying to get the focused element you should, however, query the CanExecute method so that you only determine the target object if the command can be executed. If you want to enable/disable the copy button based on the outcome of the CanExecute method, some additional work is required.
Note: This post suggests that there might be some problems using the focus manger with the DataGrid.

Related

C# Winforms Enable/Disable button based on function

I want a button on my winform to be enabled or disabled based on the return value of a particular function. Basically, I'm trying the following code in various places where the function will possible return a different value:
btnNewNotices.Enabled = isSelectedPrinterValid();
this.btnNewNotices.Refresh()
However, this is not working. Why is it when I call the refresh method after the enabled property is changed, that the button does not become enabled? I have to close the form and reopen it before the button properly disables. What is the best way to accomplish what I need here without having to bounce the form?
you can add a Databinding for the Enabled property.
if your method is implemented in your Form then you can define a Property
public bool IsSelectedPrinterValid
{
get{ return this.isSelectedPrinterValid(); }
}
And add a Databinding as following:
btnNewNotices.DataBindings.Add("Enabled", this, "IsSelectedPrinterValid");
You can refresh your value:
btnNewNotices.DataBindings[0].ReadValue();
The common way is to implement a ViewModel containing all Properties and Methods you need and bind your controls to these.
Short answer, but it's pretty straight forward.
Using .Refresh(); causes the button to repaint itself, and resets the Enabled property. There's no reason to use it in your context. Just remove it.
btnNewNotices.Enabled = isSelectedPrinterValid();

How to detect if the mouse is directly over an object type in WPF

I need to detect (true or false) if my mouse is over a specific type of object. There is one data template that the many objects use. I do not need anything from an instance of an object, I just need to detect if my mouse is above this type of element on the UI.
It would be something along the lines of:
If(mouse.DirectlyOver == StorageElementWrapper)
{
...
}
EDIT: my error is that I am using my type like a variable
It's important to note that DirectlyOver will very likely find something inside your element rather than the element you're actually looking for. To use this property, you'd want to look at the parent tree of the DirectlyOver element. Something along these lines, with FindAncestorOrSelf coming from this blog post:
if (Util.FindAncestorOrSelf<StorageElementWrapper>((DependencyObject)mouse.DirectlyOver) != null)
{
...
}
Or if you have code references to your StorageElementWrappers, (in this example, in a collection named myWrappers) and they derive from UIElement, this would probably be a better approach, using the IsMouseOver property:
if (myWrappers.Any(x => x.IsMouseOver))
// do something
I was able to put the MouseEnter event in the border of my data template. This template is bound to my objects. Instead of trying to determine if the mouse was hovering over the object before performing an action, the
object_MouseEnter(object sender, MouseEventArgs e)
{
if(....)
else
}
event fired each time an object was "entered into by the mouse" and I used conditional statements to decide how to handle the event.
Thanks for the previous suggestions regarding mouse events.
A concept if you are interested in a particular item: create an OnMouseOver handler for that particular object (alternatively OnMouseEnter). Generally in WPF things work this event handling way rather than imperatively enumerating and discovering where is the mouse pointer. So this way the item itself can tell you if the mouse is over it. The item can have a public readonly property which exposes that, and your code can just get the value of that property.

Blindly calling a public method (C#)

OK, weird one. I have many usercontrols with a repeater, the layout of the repeater is the same in all controls, and they all have a bindData() method publically available.
I'm wondering, can I setup another usercontrol for paging without having to specify the parent control?
I'm able to do the following:
((controls.specificuserControlClass)Parent).bindData();
Which is all fine - however I'd need to specify the specificuserControlClass into the pager and then would need it "per repeater" if you see what I mean?
So can I call Parent.bindData() blindly from the child control? I "know" that method exists (or would build checks to make sure), however Visual Studio isn't happy as it doesn't know of the method.
Why not make your controls all implement a specific interface?
public interface IBindData
{
void bindData();
}
Then, you would simply do:
((IBindData)Parent).bindData()
And it should invoke each control's method as appropriate.

MenuItem keyboard shortcuts in 'pure' MVVM?

All menus/contextmenus/toolbars I use in wpf are declared in ViewModel code pretty much like this:
MenuService.Add( new MenuItem()
{
Header = "DoStuff",
Command = new relayCommand( DoStuff, () => CanDoStuffExecute() )
// some more properties like parent item/image/...
} );
The MenuService provides a single binding point which is a hierarchical list of MenuItem and gets bound to the actual Menu's ItemsSource in xaml.
This works very well and now I'd like to add keyboard shortcuts in the same convenient way.
Ideally MenuItem would get a property of type System.Windows.Input.KeyGesture so I can simply write
Shortcut = new KeyGesture( Key.D, ModifierKeys.Control )
which would result in the Command of the item being called upon hitting Ctrl+D in the window that owns the menu, and which would also lead to automatically display "Ctrl+D" in the menu.
However I'm lost here: I wanted to set the MenuItem.InputBindings collection via databinding but it is get-only. How can I get items into it anyway? Or is there an MVVM framework that already supports something like this? Most q&a I found on keyboard shortcuts are all about setting the shortcuts through xaml, which is of no help.
Update
Searching for 'relaycommand vs routeduicommand and 'relaycommand keygesture' etc did reveal enough information to come up with a working though hacky solution. There are definitely other and better ways out there, but at the moment this is ultra low priority for me and does the job perfectly. I added two properties to the MenuItem class like this:
//Upon setting a Gesture, the original command is replaced with a RoutedCommand
//since that automatically gives us proper display of the keyboard shortcut.
//The RoutedCommand simply calls back into the original Command.
//It also sets the CommandBinding property, which still has to be added to the
//CommandBindingCollection of either the bound control or one of it ancestors
public InputGesture Gesture
{
set
{
var origCmd = Command;
if( origCmd == null )
return;
var routedCmd = new RoutedCommand( Header,
typeof( System.Windows.Controls.MenuItem ),
new InputGestureCollection { value } );
CommandBinding = new CommandBinding( routedCmd,
( sender, args ) => origCmd.Execute( args.Parameter ),
( sender, args ) => { args.CanExecute = origCmd.CanExecute( args.Parameter ); } );
Command = routedCmd;
}
}
//CommandBinding created when setting Gesture
public CommandBinding CommandBinding { get; private set; }
So this gives the functionality I asked for originally (ie adding keyboard shortcuts in code where they are easily configurable etc). All that is left is to register the commandbindings. At the moment this is done simply by adding all of them to Application.Current.MainWindow.CommandBindings.
This doesn't actually qualify as an 'answer' (I'm not able to add a comment evidently) - but I'd suggest that what you're doing, is not the intended method in WPF. You're doing this the Windows Forms way (and as in many other toolkits) - defining your UX in code. You got as far as you did, but now you've run into a brick wall: the key gestures are purely UX, definitely not to be specified in code-behind. The appearance (as a function of the view-model), and the user's interaction with it (ways of making a given command happen) are for the XAML definition.
Property values, and Commands are for your view-model, so that you can reuse this view-model for other views, and also easily create unit-tests for it. How would implementing your keyboard shortcuts in the view-model help the testability? And for use in other views, one could argue that the actual shortcuts might not apply to a new view, so that is not where those belong. You may have other reasons of course - but I'd suggest you might consider just defining these in XAML.
-Added, in response to your comment-
You're quite right - and I've seen some rather large WPF UX projects that tried hard to avoid any code-and wound up unnecessarily obtuse. I try to just use whichever approach yields a working result, and is as simple as I can get it.
Here is a sample snippet that simply creates the MenuItem..
<Menu x:Name="miMain" DockPanel.Dock="Top">
<MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/>
That creates the menu. Here, MyGreatCommand is an ICommand, and is simply a property on the view-model. I generally place that within a DockPanel, to handle the StatusBar, etc.
To assign the key gesture..
<Window.InputBindings>
<KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/>
However, since you mentioned that you've already searched for answers and found only XAML - I assume you've already tried this approach. I have used RoutedUICommands instead of user-defined ICommands, to get that nice right-aligned key-gesture in the header text, but I haven't found how to do both. If you insist upon creating the commands and key-gestures all in code, you may have to create RoutedUICommands.
Why are you wanting to set the key-gestures in other than your XAML?
If you want some menu-items to appear only when certain states hold sway within your view-model, then you can bind the Visibility property of a menu-item (which can contain other menu-items) to Collapsed or Visible.

How do you manually refresh a window in WPF?

I'm using the ICommand interface to perform binding on a couple of buttons in my application, the Run and Close button. I'm using a helper method that was mentioned in this question to hook up the ICommand to a delegate as follows:
_someCommand = new DelegateCommand(this.DoSomething, this.CanDoSomething);
private ICommand _someCommand;
public ICommand SomeCommand
{
get { return _someCommand; }
}
private void DoSomething(object state)
{
// do something here
}
private bool CanDoSomething(object state)
{
// return true/false here is enabled/disable button
}
This appears to work just fine as, in my implementation, CanDoSomething returns the value of a property that I have in my application.
If I set the initial value of the property to true, then the button is enabled and false it is disabled.
I have a series of events that are raised from a BackgroundWorker in the application layer back to the ViewModel that change the value of the property to true or false based on the current state of the application.
The current problem I'm having is that the button is not "re-enabling" when I set the value to true after the work has completed. If I click somewhere within the window, it will update. So, therefore, I'm thinking than manually refreshing the window will solve my problem, at least for the interim. This feels a bit gross to do it this way, but I'm kind of at a loss for what else I could try.
If anyone has any suggestions, I'm all ears.
Thanks for the help!
Ian
Edit -
A little bit more information on the application itself. It uses a background worker in the application thread to handle the "work". The application is a simple utility to manage the creating of tables and loading of data into the tables. We use a lot of pre-defined SQL scripts to setup our test environment, so this is a simple utility that allows us to do that sort of thing based on parameters provided by the user in the UI.
Hopefully that helps, because when I re-read my question it read as if I were doing everything in the UI thread, which is not the case. Progress reports are raised back up to the UI thread and everything is updated as expected, except the button..
CommandManager.InvalidateRequerySuggested() may be the answer - it tells all the commands to check whether they are enabled or not.
You have to raise the CanExecuteChanged event:
http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.canexecutechanged.aspx
This may be more useful than the other answer in cases where you know you should re-evaluate a single control, and re-evaluating all the controls would be costly. The other answer is simpler if you don't have a case like that, though.

Categories