WPF MVVM Can I bind 2 commands to a single ModernButton? - wpf

I might be going completely wrong here but I am trying to perform 2 actions based on a single click of a ModernButton (Part of ModernUI).
Basically I have an 'Add' button on one page. When a user clicks it I want to call a 'Add' method on my underlying ViewModel and also navigate to a new view. I currently have this working from 2 separate buttons as a test but want them both working from one.
Example buttons:
<mui:ModernButton x:Name="btnAdd" Command="{Binding AddCommand}" CommandParameter="{Binding Project}"/>
<mui:ModernButton x:Name="btnAdd2" Command="NavigationCommands.GoToPage" CommandParameter="/View/pages/ProjectView.xaml"/>
I think I am getting confused as its a combination of 1 action on the UI and 1 on the ViewModel underneath.
It seems like a straightforward requirement which makes me think I may be going wrong in my approach.
As always, any help is very much appreciated.
Thanks.

You can always copy the way Microsoft implements this problem, see the CompositeCommand, and either bind directly to this command, or create a multivalueconverter which takes multiple commands and returns a CompositeCommand.

Related

Binding of a button click command in c#

I have a following piece of XAML which binds a button click using prism. Can someone guide how can I achieve the same behavior in code behind since I need to create the button dynamically? Thanks.
<telerik:RadButton Margin="2"
TabIndex="3"
prism:Click.Command="{Binding cmdNew}">
EDIT : One thing I missed to mention in my post was that these command names are stored in database and I need to generate these command objects on the fly. So in this case if "cmdNew" was stored in db and I had to bind it dynamically to the button how would I go about doing that? I have looked at DelegateCommand but not sure if that can be helpful in this scenario. Your response is much appreciated.
Click.SetCommand(button, <value>)
Use the event (I think it is called) Click = "NameOfMethod" ), where NameOfMethod is a method in your cs file belonging to the screen.
When the button is clicked, the method NameOfMethod will be called.

MVVM UI update after command executed dialog closes

Hey a similar question has been asked before, but none that answers mine exactly.
I have an MVVM aplication that includes an "Options" button - click this and the options dialog opens - this is done via a command.
Once the user has saved their options, I want to tell the main shell to reload its options. What is the best way of doing this?
My button looks like this:
<Button Width="50" Command="{Binding SettingsCommand}" CommandParameter="" ...>
<Image Source="Images/Settings.png" Width="16" Height="16" />
</Button>
Thanks,
Dave.
The standard way is to implement INotifyPropertyChanged on your viewmodel, and have your command fire the PropertyChanged event after it's done changing properties (which in this case would be after the dialog closes). When you fire PropertyChanged, your bindings will read the new property values.
main shell to reload its options
Thats usualy acieved using DataBinding. When you are closing this dialog, simply update values in your ViewModel and it should bind to View easily.
It looks, like your understanding of MVVM is little wrong.
I suggest having an OptionsService that the ViewModel uses within the Dialog. Save changes to the service and if any dependent VM's need to change the display state based on the options change then they register (via an event) on the service that the options have changed. The service would also have a way to get the options data as well.
If you use Dependency Injection then this should be straight forward as you can inject an IOptionsService into all the ViewModels.

Relay/Delegate Command & InputGestures

I want to have a command from my view model associated with F8, and don't know a great deal about input gestures. Must I wrap it in a routed command or is there another recommended way to do this?
Cheers,
Berryl
UPDATE
My original posting really had two pain points in them. The first was that prior to WPF 4 you couldn't bind a command directly to an input gesture or count on visual inheritance for the command's DataContext, and had to go through a CommandManager layer. That seems like the reason the MVVM Toolkit's CommandReference that NVM pointed out was useful, but now with WPF 4 this is fixed as the Command is an attached DP on the InputBinding, so all you need to do is something like:
<DataGrid.InputBindings>
<KeyBinding Command="{Binding MyViewModel.MyCommand}" Key="F8" />
</DataGrid.InputBindings>
The second pain point to realize is that binding an input gesture to a command is not the same as associating the textual representation of that gesture to a menu item. So I need to do something like:
<MenuItem Header="{x:Static s:Strings.MyHeaderString}" Command="{Binding MyViewModel.MyCommand}"
InputGestureText="F8"/>
I spelled this out in the hopes that someone will either tell me I've got something wrong (or right). Assuming this is the best you can do then it's down to how much DRYness you can get and how to do that while keeping strictly visual elements out of your ViewModels. You could do this either by having some properties on your Command (ie, KeyGesture, KeyModifier) or having the "F8" in a resource file I suppose, depending on how much you need to reuse something and your point of view. Also on how many input gestures you have for the command!
How do I associate a keypress with a DelegateCommand in Composite WPF?
This is your answer. Instead of Key="X" you should use Gesture="F8"

WPF: Adorning a ViewModel?

I have these ViewModels: RecordViewModel, ComponentViewModel where RecordViewModel essentially is a container for several ComponentViewModels.
The display of these ViewModels is currently handled by DataTemplates that look something like this:
<DataTemplate DataType="{x:Type vm:RecordViewModel}" >
<ItemsControl ItemsSource={Binding Components} />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ComponentViewModel}" >
<TextBox Text={Binding Name} />
</DataTemplate>
What I wanted to provide now is a way to change the order the ComponentViewModels are displayed and to remove a certain ComponentViewModel from the list. I started out doing that by manipulating the DataTemplate of the ComponentViewModel and adding buttons that provided these functions (the click would then trigger a method on the ComponentViewModel that would (through a reference "Parent" to the RecordViewModel) call a method on the RecordViewModel to perform the operation (like component.Parent.DeleteComponent(this)).
The problem with this in my oppinion is that it is really the Record that should manipulate the Components position/remove a Component and not the Component itself.
So I thought about using an adorner that attaches to the RecordViewModel and renders the buttons to provide the functionality (remove, move up, move down) for each of the ComponentViewModels.
The problem however is that these adorners need to take a reference to a Control-derivate which they adorn (which was ok I would just bind to the ItemsControl in the Record-DataTemplate) however the problem appears when I want to show the buttons in the right position for each ComponentViewModel. I only have a reference to the given ComponentViewModels and not to their visual representation (the thing defined in the DataTemplate) so I have no way of knowing where to place the 3 buttons.
Is there a way to work around this? Or is it possible that for these requirements using ViewModels/DataTemplates is just not a good idea and should I therefore use Control-derivates/ControlTemplates?
Thanks in advance!
Coming up with wacky architectural hacks that you can employ to keep your view model elegant and simple is missing the point. The view model is the wacky architectural hack.
The only reason - seriously, the only reason - that the view model exists is to model the view. Does the view have buttons that trigger commands? The commands belong in the view model.
Thinking, "it's really the Record's responsibility to move Components" seems sensible on its face, but it's actually an indication that you're losing track of why you even created a view model in the first place. Does the Component view have a "Move Up" button? Then the Component view model needs a "Move Up" command that you can bind the button to. Because that's what the Component view model is for.
I'm being emphatic about this because this is the third or fourth question I've seen this week from WPF developers who seem to have gone down so deeply down the rabbit hole of the MVVM pattern that they've forgotten why it exists.
If your goal is to have a Command on the parent ViewModel that acts on an element of the child ViewModel, you can do this by using a RelativeSource binding on Command and passing the item as Command Parameter:
<DataTemplate DataType="{x:Type vm:ComponentViewModel}" >
<Button
Command="{Binding DataContext.RemoveCommand,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
Content="{Binding Name}"/>
</DataTemplate>
The RelativeSource binding will find the ItemsControl, so the DataContext property will be your RecordViewModel. The CommandParameter will be the individual ComponentViewModel, so your ICommand implementation would be:
DeleteComponent((ComponentViewModel)parameter);
it is really the Record that should manipulate the Components position/remove a Component and not the Component itself
As far as your model objects go, that's probably true. However, the ViewModels are all about presentation, and the buttons are kind of part of a Component's presentation. So I think it could be acceptable for the ComponentViewModel to have a reference to its parent RecordViewModel, to enable this scenario, even if it wouldn't be appropriate for the Component to have a reference to its parent Record.
But consider that, in your scenario, maybe the ComponentViewModel has too many responsibilities. It belongs to the collection (because it's mutating the collection), and it belongs to the element in the collection (because it's showing the Component's name in a TextBox). It sounds like it's this dual responsibility that's bothering you. So break it up. Make RecordViewModel contain RecordElementViewModels, each of which knows how to remove itself from the Record; and each RecordElementViewModel contains a ComponentViewModel. On the view side, it sounds like your UI would be composed the same way: an outer panel with a Delete button, and then another control or panel inside that, presenting the Component's properties.
Now, for the example you posted, where Component's view is just a TextBox, I wouldn't bother splitting the ViewModel into two parts. But for a more complex example, it might make a lot of sense.
To specifically answer your question about adorning:
You're getting into changing the way a DataTemplate-d element is laid out, which means you're not just layering an adorner on top of the element, you're actually wanting to insert a panel into the visual tree that imposes its own layout onto the DataTemplate (which becomes a child of the new panel). I'll admit that I haven't used adorners, but that doesn't seem to be what they're for.
The best way to do this, IMO, is to have your DataTemplate generate the parent panel, buttons and all -- which leads back to wanting the functionality on the ComponentViewModel, or perhaps splitting ComponentViewModel's responsibilities (see my other answer).

How to create databinding over two xaml files?

I am trying to come to a working understanding of how databinding works, but even after several tutorials I only have a basic understanding of how databinding works. Thus this question might seem fundamental to those more familiar with silverlight. Even if it is trivial, please point me to some tutorial that deals with this problem. All that I could find simply solved this via adding the data binding on a parent page.xaml (that i must not use in my case).
For the sake of this example let us assume, that we have 5 files:
starter.cs
button1.xaml + codeBehind
button2.xaml + codeBehind
The two buttons are generated in code in the starter(.cs) file, and then added to some MapLayer
button1 my_button1 = new button1();
button2 my_button1 = new button2();
someLayer.Children.Add(my_button1);
someLayer.Children.Add(my_button2);
My aim is to connect the two buttons, so that they always display the same "text" (i.e. my_button1.content==my_button2.content = true;). Thus when something changes my_button1.content this change should be propagated to the other button (two way binding).
At the moment my button1.xaml looks like this:
<Grid x:Name="LayoutRoot">
<Button x:Name="x_button1" Margin="0,0,0,0" Content="{Binding ElementName=x_button2, Path=Content}" ClickMode="Press" Click="button1_Click"/>
</Grid>
But everthing that i get out of that is a button with no content at all, it is just blank as the binding silently fails.
How could I create the databinding in the context I described? Preferably in code and not XAML ;)
Thanks in advance
The chunk of documentation you need to read is this: XAML Namescopes
Your button1 xaml has a binding looking for an element with the name "x_button2". However in a real application there can be many controls which in turn have nested controls. All of these controls have all manner of UI elements some of which may have names.
It would be impossible to get anything done if all names throughout the entire application had be unique. Yet that would need to be true if it were for your button1 to be able to hunt down the existence of another control somewhere in the visual tree outside of that which it actually knows (its own xaml).
Hence each loaded Xaml document exists in its own "namescope" and the search for other elements with other names is limited to that "namescope".
The are various solutions to this problem depending on what you real requirements are as opposed to the simplified problem in your question.
Typically you give each of your controls a DependencyProperty to which the inner button Content property binds. In "MapLayer" as call it, could then bind the propert on one of your button controls to the other.

Resources