Suppose I have a modal dialog with a textbox and OK/Cancel buttons. And it is built on MVVM - i.e. it has a ViewModel object with a string property that the textbox is bound to.
Say, I enter some text in the textbox and then grab my mouse and click "OK". Everything works fine: at the moment of click, the textbox loses focus, which causes the binding engine to update the ViewModel's property. I get my data, everybody's happy.
Now suppose I don't use my mouse. Instead, I just hit Enter on the keyboard. This also causes the "OK" button to "click", since it is marked as IsDefault="True". But guess what? The textbox doesn not lose focus in this case, and therefore, the binding engine remains innocently ignorant, and I don't get my data. Dang!
Another variation of the same scenario: suppose I have a data entry form right in the main window, enter some data into it, and then hit Ctrl+S for "Save". Guess what? My latest entry doesn't get saved!
This may be somewhat remedied by using UpdateSourceTrigger=PropertyChanged, but that is not always possible.
One obvious case would be the use of StringFormat with binding - the text keeps jumping back into "formatted" state as I'm trying to enter it.
And another case, which I have encountered myself, is when I have some time-consuming processing in the viewmodel's property setter, and I only want to perform it when the user is "done" entering text.
This seems like an eternal problem: I remember trying to solve it systematically from ages ago, ever since I've started working with interactive interfaces, but I've never quite succeeded. In the past, I always ended up using some sort of hacks - like, say, adding an "EnsureDataSaved" method to every "presenter" (as in "MVP") and calling it at "critical" points, or something like that...
But with all the cool technologies, as well as empty hype, of WPF, I expected they'd come up with some good solution.
At critical points, you can force the binding to push through to your view model:
var textBox = Keyboard.FocusedElement as TextBox;
BindingOperations.GetBindingExpression(textBox, TextBox.TextProperty).UpdateSource();
Edit:
OK, since you don't want hacks we have to face the ugly truth:
In order to implement a clean view, the properties exposed by your view model should be friendly to frequent binding updates.
An analogy we can use is a text editor. If the application was a giant text box bound to a file on disk, every keystroke would result in writing the whole file. Even the concept of saving is not needed. That's perversely correct but terribly inefficient. We all immediately see that the view model needs to expose a buffer for the view to bind to and this re-introduces the concept of save and forces state handling in our view model.
Yet, we see this is still not efficient enough. For even medium-sized files the overhead of updating the whole-file buffer on every keystroke becomes unbearable. Next we expose commands in our view model to efficiently manipulate the buffer, never actually exchanging the whole buffer with the view.
So we conclude that in order to achieve efficiency and responsiveness with pure MVVM, we need to expose an efficient view model. That means that all text boxes can be bound through to properties with no ill effects. But, it also means that you have to push state down into the view model to handle that. And that's OK because a view model is not the model; it's job is it to handle the needs of the view.
It's true that we can rapidly prototype user interfaces by taking advantage of shortcuts like binding on focus changes. But binding on focus changes can have negative consequences in real applications and if so then we should simply not use it.
What is the alternative? Expose a property friendly to frequent updates. Call it the same thing as the old inefficient property was called. Implement your fast property using the slow property with logic that depends on the state of the view model. The view model gets the save command. It knows whether the fast property has been pushed through to the slow property. It can decide if when and where the slow property will be synched to the model.
But you say, haven't we just moved the hack from the view to the view model? No, we have lost some elegance and simplicity, but go back to the text editor analogy. We have to solve the problem, and it is the view model's job to solve it.
If we want to use pure MVVM and we want efficiency and responsiveness, then lame heuristics like let's avoid updating the binding source until the element loses focus won't help. They introduce as many problems as they solve. In that case, we should let the view model do its job, even if means adding complexity.
Assuming we accept it, how can we manage the complexity? We can implement a generic wrapper utility class to buffer the slow property and allow the view model to hook its get and set methods. Our utility class can auto-register for save command events to reduce the amount of boilerplate code in our view model.
If we do it right, then all the parts of the view model that were fast enough to be used with property changed binding will all still be the same, and the others that were worthy of asking the question "Is this property too slow?" will have a small amount of code to address the issue, and the view is none the wiser.
This is a tricky one and I agree a non-hack and more-or-less code free solution should be found. Here are my thoughts:
The view is responsible because it sets IsDefault to true and allows for this 'problem'
The ViewModel should not be responsible in any way to fix this it might introduce dependencies from VM to V and thus breaking the pattern.
Without adding (C#) code to the View all you can do is either change bindings (e.g. to UpdateSourceTrigger=PropertyChanged) or add code to a base class of the Button. In the base class of the button you might be able to shift focus to the button before executing the command. Still hack-ish but cleaner than adding code to the VM.
So at the moment the only 'nice' solutions I see require the view developers to stick to a rule; set the binding in a specific way or use a special button.
I would add a Click event handler for the default button. The button's event handler is executed prior the command will be called, so the data bindings can be updated by changing the focus in the event handler.
private void Button_Click(object sender, RoutedEventArgs e) {
((Control)sender).Focus();
}
However, I don't know if similar approach can be used with other shorcut keys.
Yes, I have quite some experience. WPF and Silverlight still have their pain areas. MVVM doesn't solve it all; it is not a magic bullet and the support in the frameworks is getting better but still lacks. E.g., I still find editing deep child collections a problem.
At the moment I handle these situations case by case because a lot depends on the way the individual view have to work. This is what I spend most of my time on because I generate a lot of plumbing using T4 so I have time left for these quirks.
The problem is that the TextBox's text has a default source trigger of LostFocus instead of PropertyChanged. IMHO this was a wrong default choice since it is quite unexpected and can cause all sorts of problems (such as the ones you describe).
The simplest solution would be to always explicitly use UpdateSourceTrigger=PropertyChanged (as the others suggested).
If this isn't feasible (for whatever reason), I would handle the Unloaded, Closing or Closed events and manually update the binding (as shown by Rick).
Unfortunately it seems that certain scenarios are still a bit problematic with a TextBox, so some workarounds are necessary. For example, see my question. You might want to open a Connect bug (or two) with your specific problems.
EDIT:
Pressing Ctrl+S with focus on the TextBox, I would say the behavior is correct. After all, you are executing a command. This has nothing to do with the current (keyboard) focus. The command may even depend on the focused element! You are not clicking on a button or similar, which would cause the focus to change (however, depending on the button, it may fire the same command as before).
So if you want to only update the bound Text when you lose focus from the TextBox, but at the same time you want to fire a command with the newest contents of TextBox (i.e. the changes without it having lost focus), this does not match up. So either you have to change your binding to PropertyChanged, or manually update the binding.
EDIT #2:
As for your two cases why you cannot always use PropertyChanged:
What precisely are you doing with StringFormat? In all my UI work so far I use StringFormat to reformat data I am getting from the ViewModel. However, I am not sure how using StringFormat with data which is then again edited by the user should work. I am guessing you want to format the text for display, and then "unformat" the text the user enters for further processing in your ViewModel. From your description, it seems it isn't "unformatted" correctly all the time.
Open a Connect bug where it isn't working as it should.
Write your own ValueConverter which you use in the binding.
Have a separate property with the last "valid" value and use that value in your ViewModel; only update it once you get another "valid" value from the property you use in databinding.
If you have a long-running property setter (ex. a "validate" step), I would do the long-running part in a separate method (getters and setters should normally be relatively "fast"). Then run that method in a worker thread/threadpool/BackgroundWorker (make it abortable so you can restart it with a new value once the user enters more data) or similar.
What you think about proxy command and KeyBinding to ENTER key?
EDITED:
There we have one utility command (like converter), which requires knowledge about concrete view. This command can be reused for any dialog with same bug. And you add this functionality/hack only in view where this bug exists, and VM will be clear.
VM creates to adapt business to view and must provide some specific functionality like data conversion, UI commands, additional/helper fields, notifications and hacks/workarounds. And if we have leaks between levels in MVVM we have problems with: high connectivity, code reuse, unit testing for VM, pain code.
Usage in xaml (no IsDefault on Button):
<Window.Resources>
<model:ButtonProxyCommand x:Key="proxyCommand"/>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding Source={StaticResource proxyCommand}, Path=Instance}"
CommandParameter="{Binding ElementName=_okBtn}"/>
</Window.InputBindings>
<StackPanel>
<TextBox>
<TextBox.Text>
<Binding Path="Text"></Binding>
</TextBox.Text>
</TextBox>
<Button Name="_okBtn" Command="{Binding Command}">Ok</Button>
</StackPanel>
There used special proxy command, which receive element (CommandParameter) to move focus and execute. But this class requires ButtonBase for CommandParameter:
public class ButtonProxyCommand : ICommand
{
public bool CanExecute(object parameter)
{
var btn = parameter as ButtonBase;
if (btn == null || btn.Command == null)
return false;
return btn.Command.CanExecute(btn.CommandParameter);
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
if (parameter == null)
return;
var btn = parameter as ButtonBase;
if (btn == null || btn.Command == null)
return;
Action a = () => btn.Focus();
var op = Dispatcher.CurrentDispatcher.BeginInvoke(a);
op.Wait();
btn.Command.Execute(btn.CommandParameter);
}
private static ButtonProxyCommand _instance = null;
public static ButtonProxyCommand Instance
{
get
{
if (_instance == null)
_instance = new ButtonProxyCommand();
return _instance;
}
}
}
This is just idea, not complete solution.
Related
When should I use the Command and when to use the Click event?
F.e. if I have a Button in my UWP app what should I use?
When should I use the Command and when to use the Click event?
Yours is a broad question and I would simply answer with: "It depends".
Because:
The Command implements the ICommand interface and this means more code to add to your application but usually this won't change. Instead, the event handler doesn't require any interface implementation.
For every command you want, you have to provide the code that will handle the click and the CanExecute logic, to say when the command can execute. This is not requested in a simple event handler (like MyButton_Click). This means that, using a Command, you will have more control over the elements of your UI (the button won't execute anything if CanExecute is false).
When you want to add a Command, you will bind it to your DataContext (the ViewModel, if you implement the MVVM pattern). Instead, when you add a simple event handler (like MyButton_Click), the code will be placed in your code-behind that is the logic behind your main window. This means that implementing a Command, according to me, you'll have everything you need to modify in just one place (the ViewModel) instead of logic scattered everywhere in your project.
Of course, you can use whatever you want and my points are there just to give you an insight about these different implementations and you have to consider which solution is suitable for you, considering also the requirements you have been given (like: "Don't use event handlers" or "The Command is too advanced, let's just use something simple", etc.) and/or other constraints in your project.
I have an application with several tabs. One of these tabs is a "Report" tab that acts as an output console. When I first run the application, I read a file and write maybe 2000 lines to the Textbox. This works fine when a tab that is not the "Report" tab is active.
However, should I be viewing the "Report" tab (with the Textbox) whilst it is having a lot of data written to it, the application writes one or two lines of data and then will not respond. The whole application crashes.
The code I am using to update is quite simple:
string timestamp = DateTime.Now.ToString("H:mm:ss");
string output = this.textbox_report_output.Text;
output += timestamp + ": " + message + "\n";
this.textbox_report_output.Text = output;
this.textbox_report_output.ScrollToEnd();
I have had very bad performance with WPF's Textbox when putting it under this kind of stress. Is there anything I can do?
I have had very bad performance with WPF's Textbox when putting it under this kind of stress. Is there anything I can do?
Yes, you can write WPF properly instead of pretending that it is Windows Forms.
In WPF, we use data binding to update the UI instead of procedural code. I suggest that you have a good read of the Data Binding Overview page on MSDN to get you started, but it basically goes like this:
Create a string property and implement the INotifyPropertyChanged interface:
public string Text { get; set; } // Implement the INotifyPropertyChanged interface
Data bind it to the TextBox.Text property:
<TextBox Text="{Binding Text}" />
Set the value:
Text = "Some value";
Use the Dispatcher to run the UI updates while you are still executing other code:
Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate { Text = "Some value"; });
Obviously there is something wrong beyond what I'm about to say but since you are using WPF, there's a better way to update the UI than you are using. Instead of pushing the updates like you are doing, you could let the WPF binding system take care of the logistics of updating the UI.
This way, the updates won't flood the UI thread. To do that, either create a DependencyProperty (or implement INotifyProperty changed) and then bind the text box to the property.
That said, if the application is crashing you're probably doing something else wrong. Maybe you're leaking memory and your getting an OutOfMemoryException?! Or perhaps some threading issue?!
I would agree with the other two responses that data binding is the best option for wpf textbox input and output. But, in some cases you do not have that luxury, especially, when the data you need is on a view and control you are accessing are via remoting and formatting the UI output is important.
If you are setting the Textbox.Text field in the OnTextChanged event (while in Japanese or Chinese and your entry is full width), then there is a high chance that it will crash your system. Try, instead to capture the LostFocus event, then make corrections there. Then, it us safe to set the value in the Textbox.Text field. Also, you can intercept the KeyDown event and remove non-numerical keys except the decimal point.
I'm trying to perform some actions at my VM just before my Window closes, It mean I need DataContext must be available for my actions.
Actually I'm trying with this:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding _MyCleanUpCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But, at this point all objects on my ViewModel are cleaned and my DataContext = null
What is the propper event to Bind with my command?
There is a way to force one class to execute Automatically a method when this is no needed anymore (Needed mean in my current proccess)?
NOTE: For the second question IDisposable does'nt work due must be called manually. ~ Finalizers doesn´t work inmediatelly.
First of all the objects are not being cleaned.
The name of the event you are trying to listen to is called "Closing" which is being fired before the actual close. The event that signals to you that a window got completely closed is called "Closed". Those are the two events available for you.
I would simply associate the handler in the View constructor
MyWindow()
{
// Set up ViewModel, assign to DataContext etc.
Closing += viewModel.OnWindowClosing;
}
Then add the handler to the ViewModel:
public void OnWindowClosing(object sender, CancelEventArgs e)
{
// Handle closing logic, set e.Cancel as needed
}
In your case, you gain exactly nothing except complexity by using a more elaborate pattern with more indirection (5 extra lines of XML plus command pattern).
The "zero code-behind" mantra is not the goal in itself, the point is do decouple ViewModel from the View. Even when the event is bound in code-behind of the View, the ViewModel does not depend on the View and the closing logic can be unit-tested.
However if you insist on sticking to interaction I recommend you read this link below:
http://msdn.microsoft.com/en-us/library/ms748948.aspx
It will give you an overview about events of Window.
Btw, like I already said DataContext is there for sure so I assume you rather have a bug somewhere in Command pattern (you might have defined the Command wrong). You should have posted us the complete code.
Futhermore giving names to public commands with first letter being an underscore is sooo outdated. I remember using them 20 years ago in pure C to signal a private field. :)
Your DataContext and all other objects shouldn't be already cleaned when you enter into your Closing command. This is not the expected behavior.
Indeed, the main purpose of the Closing event is to provide a way of preventing the application exit without any harm (from msdn):
When a window closes, it raises two events: Closing and Closed.
Closing is raised before the window closes, and it provides a
mechanism by which window closure can be prevented. One common reason
to prevent window closure is if window content contains modified data.
In this situation, the Closing event can be handled to determine
whether data is dirty and, if so, to ask the user whether to either
continue closing the window without saving the data or to cancel
window closure. The following example shows the key aspects of
handling Closing.
Chances are there's a bug with your EventTrigger which triggers the associated command too late in this particular scenario.
Try to simply bind your window to the Closing event in code behind and see what happens.
I have a co-worker that asked me why he has to use the ICommand pattern.
He wants to add a button and then make an event for it in the code behind. Then from the event he wants to call a method on the ViewModel.
I gave him the obvious answer: This adds coupling between the View and the ViewModel. But he argued that the View and the ViewModel are already coupled. (We set our view's DataContext to the ViewModel in the View's code behind: DataContext = new MyViewModel();
Yes, I told him that his way adds "more coupling", but it sounded a bit lame even to me.
So, I know that ICommand is the clean way, and I do it that way. But what else does ICommand buy you besides not using an already existing coupling?
It's not about decoupling, but how deep you can penetrate inside your ModelView hierarchy: not event pumping, but event routing, built-in in the framework.
It's about UI managent: Command has state (CanExecute), if assign the command to the control, if command's state becomes false, control becomes disabled. It gives you powerful UI state management way, avoiding a lot of spaghetti coding, for complicated UI especially.
I have a co-worker that asked me why he has to use the ICommand
pattern.
It seems implied this is a standard at your company (whether explicitly stated or unspoken). That should be answer enough to his question.
If all company code is supposed to use that pattern, it can cause co-developer confusion and frustration when someone else has to debug his code.
Also, in my opinion, using ICommand is faster to develop / mock up because you don't NEED to have the ICommand property on the context to run your program. It lets your UI designers (if you are lucky enough to have them) completely finish their tasks even if you are behind in your coding.
ICommand can also give you a place for handling wether or not a specific button can be used right then. this would be handled through the canexecute method.
You can bind the CanExecute method of the command to the properties of a control, also a Command encapsulates an action in a nice way. In my opinion / experience this approach makes a lot of sense because you have both the condition and the execute action in a single abstraction, which makes it easier to understand and test.
If in the future you find that this action is repeated you can abstract it easily in your own custom ICommand and use it in several places.
One thing that I don't see in the previous answers is that using the ICommand promotes code reuse by allowing the same action to be used by different GUI components. For example, if I had a command that should result in the opening of a window and that command could be invoked in three or for different screens in the application, an ICommand implementation lets me define that logic in a single place. With the code-behind event handlers, I have to copy and paste redundant code, in violation of DRY (or else, I'd have to roll my own implementation by abstracting out to a class, at which point, I might as well use ICommand).
I'm having a problem understanding something about MVVM. My application relies on dialogs for certain things. The question is, where should these childwindows originate from? According to MVVM, viewmodels should contain only businesslogic and have zero actual knowledge about UI. However, what other place should I call my childwindows from, considering they're UI elements?
Doesn't this create tight coupling between elements?
Since you tagged the question with Prism, I'll suggest the way I've done it in the past using Prism. Have the IEventAggregator injected into your ViewModel, and then when you want to pop open the dialog, publish a "ShowDialogEvent" or something like that. Then, have another Module called "DialogModule" or whatever, which upon initialization subscribes to that event, and shows the dialog. Furthermore, if you want to pass data back to the original ViewModel, have the ViewModel of the dialog publish a "DialogCloseEvent" or something like that with a payload of the data you need. You can then subscribe to that event back in your main ViewModel.
See Handling Dialogs in WPF with MVVM
In the past, I have accomplished this by using Unity to resolve a custom interface that has a Show() method and a completed event. Then in the ViewModel I would call IScreen screen = container.Resolve<IScreen>(Resources.EditorWindowKey); and then just call screen.Show();.
The big advantage of this is that I can then just simply change my Unity configuration to remove the view when I'm testing my VM's.
The primary route I've been using to do this is to create a command inside your View layer. That command object accepts a parameter that is the ViewModel object that you want to display. The command then finds the appropriate ChildWindow, creates it and displays it with the parameter set as the content or however you will set it up. This way you can just bind a button's command property to that command, and its commandparameter to the object you want to show in the popup and your ViewModel objects never have to care how it's being displayed.
Prompting for user input (like saving a dirty file or something) doesn't work in this scheme. But for simple popups where you manipulate some data and then move on, this works very well.
The ViewModel sample application of the WPF Application Framework (WAF) demonstrates how to show a Modal Dialog.
I would suggest to use a controller in this scenario, say DI'ed dialogController backed up with a dialog shell. The source viewmodel(ie from where the request to open a dialog is originating) will make a call to dialogController.ShowDialog(<<ViewNameToHostInRegion>>,<<RegionName>>).
In Order to transfer the data to and from the dialog and sourceview you can use MessageBus. So essentially when you invoke the ShowDialog() you populate the messagebus, and when the close command of target View(The view hosted in Dialog shell) invoked - say in "Select" button -- Let the target view add/update the messagebus. So that source view model can work with updated data.
It has got many advantages :
1) Your source view works with dialog controller as BlackBox. ie it doesnt aware of what exactly the Dialog view is doing.
2) The view is being hosted in Dialog Shell -- so you can reuse the dialog again and again
3) Unit testing of source view is limited to test the actual functionality of the current viewmodel, and not to test the dialog view\view model.
One heads-up which I came across with this one is, while creating the test cases you may need to write testable Dialog controller which do not show the actual dialog while running the testcases in bunch. So you will need to write a TestableDialogController in which ShowDialog does nothing (Apart from deriving from IDialogController and provide blank implementation of ShowDialog().
Following is the psudeo code :
LocalMessageBus.AddMessage(<MessageKey>,<MessageActualContentAsObject>);
dialogController.ShowDialog(<TargetViewName_SayEmployeeList>);
Employee selectedEmployee = LocalMessageBus.GetMessage(<MessageKey>) as Employee;
if (selectedEmployee != null)
{
//doSomework with selected employee
}