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.
Related
i faced with some problems when designing architecture of my extensible programm.
I'm using MEF, MMVM Light Toolkit and AvalonDock.
The first problem is how display view for some ViewModel imported from another assembly using MEF.
To solve it, i'm exporting ResourceDictionary where i'm defining DataTemplate's for views declared in this assembly.
Dictionary:
<ResourceDictionary
...>
<DataTemplate DataType="viewmodels:MyViewModel">
<views:MyViewForViewModel/>
</DataTemplate>
</ResourceDictionary>
And in constructor of MainWindow i'm importing all ResourceDictionaries and merging them with MainWidow.ResourceDictionary.
Is it good? It's also possible to specify 'scope' of ResourceDictionary to import it not to MainWindow, but to Application for example.
The second problem is ICommands and CommandBindings.
To populate Menu i'm exporting 'MenuItems' where i'm defining ICommand, Text and other stuff, but i don't know how to export CommandBinding, should i use RelayCommand for cases when i can't create CommandBinding?
The third problem is dialogs.
I found great article Showing Dialogs When Using the MVVM Pattern and easily adapt it to MEF. But, for example, I have an IDatabaseService which don't have any View.
The Workspace, main ViewModel, storing instance of IDatabaseService and creating menu item: Connect to Database. Using IDialogService Workspace opening some imported IConnectToDbDialog so Workspace don't know anything about it. When dialog closed, the SqlConnectionString should be passed to IDatabaseService.
So who must pass this SqlConnectionString, IConnectToDbDialog or Workspace.
The fourth problem is how to communicate with IDatabaseService correctly.
For example. In some View i have Button: 'Create Item In Database'. And how should i call IDatabaseService method CreateItem(ElementType elementType) when button clicked?
The problem, that there are a lot of buttons which create Items with different ElementType in database, so, i think, it's right to create some ICommand with parametr and create only one handler for this command which will invoke some method in IDatabaseService. But i don't know how.
The other solution is to send messages to IDatabaseService from ViewModel to create item.
which way better?
Try to answer your questions.
It is good. You can merge either on XAML or code behind but I prefer XAML. You can put it on MainWindow.Xaml, which is in scope of main window or on App.Xaml, which is in application scope.
I did not export views before. In my opinion, if you put CommandBindings under Menu, it does not matter when it is exported then imported if the event handler in the scope of imported environment.
It depends. Theoretically you can put the service call in either owner's view model or dialog's view model. If your dialog have a create/submit button, for instance, and you expect the dialog keeps alive until submission is successful, then put it in dialog's view model so that you can keep it open when you handle exceptions. if you do not need the dialog keeps open, then you can put the logic in owner's view model after dialog is closed.
Command is better. Considering the view model gets IDatabaseService object from IoC container, You might have one ICommand property that accepts ElementType parameter or a paramerter can map to ElementType. In the execute method you call CreateItem passing the parameter directly or from mapper. On you XAML, you put type in the command binding. Does it make sense?
Hope it can help.
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.
I have the following:
<Button Content="Do XXX" Height="23" Name="btnXXX"
IsEnabled="{Binding Path=(Model:INameOfInterface.CanDoXXX)}" />
<Button Content="Do YYY" Height="23" Name="btnYYY"
IsEnabled="{Binding Path=(Model:INameOfInterface.CanDoYYY)}" />
Working very nicely, btnXXX is enabled or disabled according to whether the interface can do XXX, btnYYY similarly for YYY.
However, to force one action per click, I want to disable all the buttons once one of them is clicked, i.e. momentarily override the dependencies and disable the buttons and then, once action has been executed, re-establish the dependency conditions.
So my question is: How do I momentarily disable all buttons and then resume the dependencies
Typically you don't "override and resume dependency properties", but design Model/ViewModel so that a property you bind to encapsulates all required states. In your case this would mean that your Model:INameOfInterface.CanDoXXX should be true initially, and be false whenever any button action is being executed (xxx, yyy, ...). So your CanDoXXX would have to know about execution of YYY. It might be a bad idea to mix it all up in your Model and this is where ViewModel comes into play.
Assume your Model instances are only self-aware: CanDoXXX is false only if XXX is being executed. You can have a ViewModel class containing a collection of models, each with its individual state. Now, all you need is to put a property in VM, e.g. CanExecuteAny that would iterate over all models and check whether any of them is doing work (CanDoXXX, CanDoYYY indicate that). Finally bind
<Button IsEnabled={Binding CanExecuteAny} />
This is just one of potential solutions and the best one depends on exact structure of your data. Here are some other thoughts:
You could put all your buttons in a panel and disable the panel instead of individual buttons.
Implement ICommand interface and bind button's Command property to it. See RelayCommand concept. Personally I'd go for it.
Since your buttons need info whether any other button has been clicked, you might find it useful to have sort of a global state accessible to all models (perfectly dependency injection; less perfectly a singleton without DI).
Having said that, the basic idea is to have all needed info in a single property you can bind to. Swaping DPs is not really a way it was designed to work. The Binding is already there to update things, so setting it more than once is repeating the same job twice.
You can create the bool property and bind all buttons IsEnable with it. Whenever u do some action , make it false and after completing the action make it true which in turn will affect all the buttons. OR u can use spinner/Busy indicator.
I need an elegant solution (I am working on silverlight 4.0) to solve this simple problem(?) using the MVVM pattern:
My mainpage xaml has my two custom user controls like this (say):
<uc:MyCustomUC1>
<uc:MyCustomUC2>
Each one has its own view model and both these user controls are independent of each other.
When an asynchronous operation in MyCustomUC1 has completed, I want an ICommand in MyCustomUC2's viewmodel to be invoked thus refreshing data in MyCustomUC2. I want this done by the parent page and all in xaml.
Exposing dependency properties, event handlers etc in the user controls...anything is ok since I own the user control ...whatever makes sense.
Any ideas ?
Use Mvvm Lights messenger, you can register a listener in MyCustomUC2's viewmodel to refresh. Then in MyCustomUC1's async call back, send the message to refresh.
You could use a PropertyObserver, which I believe you can find info on here:
Property Observer.
It'll allow you to check when something has changed in one ViewModel and then take the appropriate action in another. I've used this quite a bit recently in a project and it has worked pretty well.
Apologies if I've picked up the question incorrectly.
I have an application in which there are lot of TextBoxes and some Buttons like Save, SaveAs,etc.
When the user edits a TextBox, I have to check the DataBase for some range, validate the range and update the DataBase.
If there is any error in value entered by user,then I should not allow the TextBox to lose focus.
I was using LostFocus event for this and it was working fine until lately I discovered a bug in my application.
Bug : The user edits a value in TextBox and then clicks on Save button; the LostFocus event is not called and so Database is not getting updated :(
Now my question is which event should I use in TextBox to update the DataBase. I tried TextChanged event but it validates for every character and making my application slow. I am confused in chosing the right event for this kind of application!
Note :** The Buttons are in different UserControl !
EDIT 1 : I have some Commands attached to click of Buttons, these Commands are getting executed before LostFocus !! Can I set precedence or something like attached behaviours or commands should get executed after LostFocus !!
EDIT 2 : I was just debugging the application by disabling some commands, what I found was in some cases, the DelegateCommand gets executed before LostFocus, so I want to avoid that. How can I go about it ? I felt during development its impossible to developa pure MVVM application so I am kind of using a bit of codebehind !
Trapping the keyboard focus within a control is usually a sign of bad UI design - it's pretty user-hostile to force the user to fix data in a control before he can type anywhere else in the UI.
That said, you shouldn't be using events at all here. You're trying to write a Windows Forms application in WPF. You should write a WPF application.
Create a class that is a logical model of your view - i.e., there's a string property for the text box and a Command property (or, more likely, a RelayCommand) for the Save button. Bind the text box to the string property, e.g.:
<TextBox Text="{Binding MyTextProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Because the UpdateSourceTrigger is PropertyChanged, the source object will get updated every time the user types a character.
Bind the button to the command property, e.g.:
<Button CommandBinding="{Binding SaveCommand}">Save</Button>
Implement the appropriate CanSave and Save methods that the RelayCommand (as described in Josh Smith's essential article on the MVVM pattern) requires, so that the button is enabled when the string property is valid and disabled when it's not.
I think the best approach is preventing a user to proceed until all valid information has been gathered.
Just like an installation wizard with Terms & Conditions Dialog and Next button. Until you check the I Agree checkbox, Next button is disabled.
This way, you don't have to worry about user proceeding without providing valid information. This way, you can use any event on TextBox to validate your data.