Momentarily disable buttons enabled through dependency properties - wpf

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.

Related

Data binding: Different triggers for different purposes

I have a WPF MVVM data form window with data validation. A lot of the controls are text boxes. Currently, the data binding trigger is set to the default, i. e. loss of focus. This means that a field is only validated when it is likely to be filled out completely. So when deleting a number and typing another number, the transient empty value will not be displayed as input error.
But a drawback is that the Save button can only be enabled when the focus moves out of the text box. (No matter where, just out of the edited control. Assuming there is anything else focusable.) If this is the only change, the user waits for the Save button to be available and nothing happens. For the Save button, I'd like to use an immediate binding trigger. How can that be done?
Edit: Forgot to mention that my Save button (which uses ICommand) is only enabled when the input is determined modified and valid. So the data will remain unmodified until data binding updates it, and that won't happen until the focus moves to another control.
I actually had a similar question a while back and the solution I ended using was a custom DependencyProperty that kicked off a timer when a key was pressed, and only actually processed the PropertyChange notification if a specific time had passed.
This means the bound property doesn't get updated (and validated) unless the user pauses in typing for a set period of times.
The code can be found here (may need a bit of cleanup), and it is used like this:
<TextBox
local:DelayedUpdateBehavior.TargetProperty="{x:Static TextBox.TextProperty}"
local:DelayedUpdateBehavior.Milliseconds="1000"
Text="{Binding MyTextProperty, UpdateSourceTrigger=Explicit}" />
Edit: Actually this link might be better. It's a markup extension so you can use it directly from your binding. I can't remember which of these two methods I used in the past, but I know it was one of them :)
<TextBox Text="{local:DelayBinding Path=MyTextProperty, Delay='00:00:01'}" />
Assuming you're using an ICommand type interface for the button click event:
You can...Implement string properties with INotifyPropertyChanged and bind them to your textbox controls. Now in your Command canexecute method you can check to see if the property is !nullorempty.
e/ grammar
Set your Binding's UpdateSourceTrigger property to PropertyChanged. The default for TextBoxes is LostFocus.
Update: So you want to have data binding working on your TextBox and only allow numbers? Have a look at this question: Create WPF TextBox that accepts only numbers
Or use a converter and bind the Save button's IsEnabled property to your TextBox (maybe using a MultiBinding if there's more than one), and use a converter which determines if the text is a valid number and returns true or false.

UI IsDirty versus Entity IsDirty

I am well aware of the INotifyPropertyChanged and INotifyCollectionChanged for WPF binding. This has been implemented and is working as expected. Therefore, changes to a property on our entities will set their "IsDirty" flag. Which in turn, turns on the Save functionality, all via binding, beautiful you may say.
However, we recently had a change request raised to request that the Save button should become enabled as soon as the field changes (i.e. use presses the first keystroke), much like the undo application command does when you type in a textbox. Therefore the save button must know when every field is changed on the form instead of the property being changed in the entity via binding.
The main reason for this request for help, is one of our forms only has one field that changes (everything else normally remains default), but the user still has to tab out of the field to enable the Save button, instead of just being able to save straight away.
You need to change the UpdateSourceTrigger to PropertyChanged
This will update the binding everytime the text changes rather than LostFocus - which is the default for a textbox.
<TextBlock Name="txtName" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />

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.

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).

Distinguish UI change to variable from code-behind change

Like the title says I am trying to architecture into my application a way to distinguish the source of a variable change, either from UI or code-behind.
My problem is that I need to trigger some action after a property changed its value, but I only need to do this when the change comes from the UI because otherwise I don-t want to perform that action. I am having some trouble because, for example when a checkbox(two way binding), changes state, my binded property gets updated and then I use the checked and uncheked events to trigger that action.The problem is that when I change the property in codebehind it also triggers those events and I do not want that. Right now, i am using a flag that enables, or not, the actions at the event handlers but I do not feel that this is a good idea.
Any sugestions or ideas?
I am considering using only one-way binding and control everything my self, using commands.
It looks like you have some confusion between your model and your controller. There shouldn't be any cases where it matters if the a change to the model comes from the user or not. If you want to have something like a confirm message it the user makes the change, then don't bind the view control directly to the model, but have the controller respond to the event.
That way, if the control is changed to be the same as the model, then the change is internal, and no confirm is required, but if the control is changed by the user, then the control state differs from the model, and a confirm can be shown.

Resources