WPF Bind different commands to button/menuitem - c#

I would like to ask you for an advice.
The application that I am working on has a docking control and should support working with different "documents". Therefore there can be multiple windows(tabs) opened at the same time.
Each can host a different content. The "documents" that I referred to could be a text file,
an excel style sheet or the main control that this app is being developed for (a geographical data visualization).
I am using the MVVM pattern and MVVM Light library. Note: I have a third party control for the excel spreadsheets.
Now I have a menu bar and a toolbar where I have common menuitems (in menubar) / buttons (in toolbar) like 'save', 'cut', 'copy' etc... When you switch between between the tabs, the 'save' button should call the appropriate save functionality.
The same goes for cut/copy/paste:
When in a tab with text document - cut/copy/paste should operate with text (there are wpf built-in commands for this).
When in the main control - It should work with the graphical elements (I will have to implement these)
When in the spreadsheet - It should work with the enclosed third party commands for the spreadsheet control.
Furthermore, there can be a tab that has some text selected - thus the menuitem/button for cut/copy should be enabled when switched to this tab, while some other tab has no graphical elements selected thus the menuitem/button for cut/copy should be disabled when switched to this tab.
With the save command I can imagine one possible way to do it, but still, I am not sure whether it is a good way to implement it: Have a RelayCommand in MainWindowViewModel
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(() => this.SaveFile());
}
return _saveCommand;
}
}
and the SaveFile() method would call some other 'save method' on the datacontext of the selected tab (which would be a viewmodel for the according "document" type).
However I don't know how to do the enabling/disabling of the save button/menuitem and I am clueless about how to achieve the different cut/copy/paste functionality.
I apologize for the length of the question. Maybe I could have just asked:
"How do you bind different cut/copy/paste commands to the buttons depending on which part of application is selected/active?".
But I felt the added context of what I am trying to achieve would help answer the question.

and the SaveFile() method would call some other 'save method' on the
datacontext of the selected tab (which would be a viewmodel for the
according "document" type).
The SaveFile should be implemented by the ViewModel without going back to the View.
Create several ViewModels to represent different kind of documents and let each implement its Save functionality.
The CanExecute method of a command can be used by the View to decide whether or not the menu item or button should be enabled. All you need is to implement the CanExecute method in the ViewModel. In most cases a Save command's CanExecute would use an IsDirty or similar property.
EDIT
For menu items that should be context/active tab item aware you could create a main ViewModel with the commands for the menu and a collection of ViewModels (one for each tab item)
In the command handlers of the context aware menu items get the active ViewModel and pass the command on.
To get the current TabItem, bind the SelectedItem to a property of the main ViewModel (the type of the property could be a base class of the ViewModels).
That way you do not need to get back to the View to get the current tab item.

Related

PRISM + TabControl + Validation = Pain

In my application I have dialogs with mutiple tabs. Im using Prism to register the views with the TabControl.
What I want is a validation for the entire dialog to diable/enable the save button.
The Problem: Currently we have a view-triggered validation. Means every bound item implements the IDataErrorInfo interface. When the View is displayed the binding triggers the interface and displays and error on the UI. The Control has the HasError Property set to true, save button gets disabled.
But the validation does not get tiggered until the view is displayed. Should I move the validation to the ViewModel and validate the Properties on my own or is there a solution to validate inactive views in a TabControl?
There isn't quite enough information to go off of I your question, so I can only guess. First off, you must understand that there are no inactive views in a TabControl. There is only one view in the TabControls visual tree at one time, and that is the selected tab. This means the other views are removed from the visual tree until they are selected. This really doesn't matter though, as validation is controlled via the ViewModel. You ViewModel most likely has a Command bound to your Save button. This command should have a CanExecute defined returning IDataErrorInfo.Error != null (meaning you have no errors). This is where you will check the validity of your objects. Return false if you have any errors, and true if you don't. Hook into the property changed event of your objects, and call the SaveCommand.RaiseCanExecuteChange method to recheck the state of your button.
If each view a tab has it's own ViewModel, hence it's own Save command, I would recommend using a CompositeCommand. This is really an unknown since I don't know how you have architected your dialogs, views, or ViewModels.

C#, WPF, MVVM, Creating a viewmodel for message dialogs/confirmation dialogs?

I am not using anything other than a simple WPF application project in visual studio. I've implemented an mvvm application.
I want to display a list of content changes made by a user. I have a main window view model and it currently just builds a strings with changes. I have objects that I can reuse to display their properties (the content).
Currently, I use a MessageBoxResult to show a really long string with the changes. This is a terrible design (I know), but I couldn't really find an answer to what class a regular wpf project has that would allow me to achieve what I want.
I know there is a popup class I can use. In practice, which is better-- another view model for the dialog, or a popup?
Can anyone provide a simple example of one of the two approaches?
Thank you in advance for your response.
What I've done in the past is have a simple Border control, and inside of a TextBlock and whatever Button controls I need. I bind the TextBlock.Text to a public string property named "MessageBoxMessage" which calls OnPropertyChanged(). I bind the Command of each Button to a separate public ICommand which specifies what action to take in the view model when the button is clicked. I then bind the visibility of the Border control - which contains all of the other controls I mentioned - to a Visibility property.
When I want to show a dialog, I set the MessageBoxMessage to the message I want to show, makes sure the commands are set properly, and then set the Visibility on the Border to Visibility.Visible. This shows the box (border), message, and buttons.
You can even implement a semi-transparent rectangle underneath the border (over the rest of the form) that you set to visible at the same time. This will give you the nice "form dimmed" effect and also block the normal form controls from being clicked. A general note - for this to work, these controls need to be at the very bottom of your XAML as the z-index among controls at the same level is inferred from their placement in the XAML - lower in the code is top level on the form.
Let me know if you have any questions about implementing this if it sounds like what you are looking for.

MVVM - Global actions that act on the "currently selected object"

I have a complex application that I am attempting to develop using MVVM (a pattern that I am new to) - the applicaton has tabs and docked windows each of which has the concept of a "selected object", and a global toolbar at the top of the application that has actions on it that need to act on the "selected object".
Imagine a slightly less complicated version of something similar to Visual Studio, for example:
If a pane is selected that contains a list view where the selected object is "inactive" then the "Activate" toolbar item should be enabled. (The global selected item is that list view item)
If however the user then clicks on a tab in another pane which has no selected object then that same toolbar item should be disabled (The global selected item is null).
Ignoring for the moment complications such as multiple selections, at the moment I have implemented this by creating an all-encompassing singleton* model class that represents the "application" itself, e.g.
class MyAppModel : INotifyPropertyChanged
{
public ISelectableObject SelectedObject { get; }
}
I then have "a system" (I admit I'm glossing over a lot of details here) in place for making sure that this property is updated (and the relevent events fired) when changes in the UI results in changes in the global "currently selected object", and the toolbar buttons use this property to determine availability etc...
However I'm getting hung up on the fact that this doesn't seem very MVVM-like (I read somewhere that UI state should be stored in the ViewModel?)
Is having a global model that represents "the application" in this way a good idea? (there are also other properties on there to keep track of other things in the application in a similar way, such as the open documents)
If not, what should I use instead to allow global components (such as items in the toolbar) to find out and keep track of what the "global selected object" is
(*) Which could just as easily be supplied using dependency injection
for MVVM you should definately have a master ViewModel that represents the top-level binding surface for your Views.That master ViewModel will have a 'SelectedItem' property that participates in the INotifyPropertyChanged notifications of the ViewModel. You should then bind your relevant ItemsControl(s) (TabControl etc) SeledctedItem to this ViewModel Property, then other parts of your app can bind to the ViewModels SelectedItem property and bindings will change automatically.
try to register PreNotifyInput event of Inputmanager.current. and register this at applicaiton level this event into global level.
InputManager.Current.PreNotifyInput += new NotifyInputEventHandler(Current_PreNotifyInput);
also refer to Inputmanager class
http://msdn.microsoft.com/en-us/library/ms617136

C#: What is the value added by commanding?

When looking into MVC frameworks for flex, as3, silverlight, and wpf... a common concept of ICommand / commanding keeps appearing... Can anyone explain the advantage of using ICommand / Execute() ?
Where I dont see the value added is - Why can't the controller map the input (ie: a click event) to the correct method inside of the model? I'm assuming it is because commanding buys you something - like removing business logic from the controller / the would-be event handler in the controller.
Thx.
Here's a couple of cases that demonstrate the value commands add:
Suppose you have a simple form with a text box and Submit button. You want a button to become enabled only if some text is entered into the text box. With commands all you have to do is to implement CanExecute method (to return true or false depending on the value in a text field) A framework will automagically disable/enable button accordingly. With code-behind (or controller) approach you'd have to write a code do enable/disable button manually.
Suppose later you decided you don't like the button control you used, and decide to switch to a new control (being that a button, or something more exotic) from a different library. All you have to do is make a change in XAML. Any control that supports Command binding will know what to do. In code-behind approach you'd have also modify your button click handler (since new control will probably require different event handler signature)
Suppose later you decide to add a checkbox to your text field that would visually indicate to user whether the content of that field is acceptable. All you have to do is to bind this new checkbox to your command's CanExecute, and now you have two controls already that would automatically change their visual appearance depending on whether form is submittable. With code-behind approach (or controller) addition of a new control would require adding more code.
Suppose you want to test your action. Since commands don't depend on any visual elements, and don't need them, you can easily write a unit test that will not require user clicking any buttons, or entering any text. With controller approach you'd have emulate controller's events, and mock the view.
Summarizing:
Commands provide a well-defined interface between the business logic and the presentation. Business logic implementor doesn't care about how visually certain action (e.g. command) will be implemented. He simply provides the action implementation and an ability for a presentation to query the state of the action. He doesn't care what particular UI element (or elements) will trigger that action, how exactly (in)ability to execute that action would reflect in UI, and what changes UI might go through in the future. At the same time presentation designer doesn't need to know anything about event handlers, controllers, etc. He has a Command and he plugs it in to any UI element (or elements) he chooses without the need to go to C# code at all.
What controller are you talking about?
The Commanding concept in Silverlight and WPF is used to tie together (through binding mostly) the UI to business logic (be it a controller/viewmodel/model/etc).
That is the point, to move the functionality of the command outside of the UI.
Example. Saving a widget in your application is probably always done the same way. Sure, you might let the user change the name, or this or that, but the overall behavior is always going to be the same. Now, in your application you might actually initiate saving a widget through a lot of different UI avenues such as Page 1 has a button on the right hand side that saves the widget on that page, Page 2 has a menu item on the top that saves the widget on that page. The UI is different but the behavior remains the same.
You can accomplish the same goal by using Event Handling (such as grabbing the click event on a button), but now you're back into the context of dealing with UI specific issues. Commanding, arguably, has a cleaner separation.
The simple answer is that commands are bindable whereas events are not. So if you want to respond to a button click event you can either:
Attach an event handler in the code behind.
Create a click command and bind it to the ViewModel's command.
Since one of the goals of MVVM (which is the more common pattern for Silverlight and WPF over MVC) is to seperate code and UI. So if you take the first approach you end up with code in the View. If you take the second approach you can seperate the code from your view using commands and bindings.

Expose multiple command in WPF user control

A better explanation, I hope:
I have a toolbar with 3 buttons on it, all three bound to a Command (including a CommandParameter)
this toolbar is used on several screens
the xaml of the toolbar is exactly the same over all those screens
I want to remove the toolbar instance and replace it with a user control that provides 3 commands, so I can keep the bindings in each screen. The plan is to later change the toolbar functionality, but the external programming interface (namely, 3 commands) is the same.
So:
I created a user control, and created 3 sets of dependency properties for each command (OneCommand, OneCommandParameter, OneCommandTarget) so I can use these for the binding.
I moved the toolbar xaml inside the user control xaml.
I modified the bindings on the toolbar buttons to bind to the intristic user control properties
on each screen (or really, only the first for now) I replaced the original toolbar with the user control,binding the new properties to the correct commands.
The control shows, but the buttons don't work.
That's about it.
--
Original explanation - not so clear:
I have a WPF user control encapsulating a number of buttons. Previously, the control was a Toolbar with a number of buttons on it, but since I need exact the same functionality on a number of screens, I refactored the toolbar into a custom control.
However, I'd like to keep the command bindings of the original buttons.
I created 3 sets of dependency properties (XCommand, XCommandParameter and XCommandTarget) on the usercontrol.
In the user control xaml I bind the "real" buttons to those properties (each button to each set of properties).
Where I use the usercontrol, I bind the new properties to the real command bindings.
In essence, I want to keep the ICommandSource functionality for each "command" that the user control exposes. However, this dual databinding scenario doesn't seem to work, or I'm doing something wrong. :)
Is there a better way to do this? All I need is to "bridge" the commands from outside the control to the inner buttons so the Execute and CanExecute functionality remains.
I solved this. There was a bug in my RelativeSource in the internal control bindings. It works fine as expected, now.

Categories