I've got a simple View with a single textbox that gets databound to a simple ViewModel with a single string property.
I need to catch the TextChanged event of that textbox so that I can do a little validation magic.
The problem that I am running into is that the TextChanged event fires for that textbox when the DataContext is set for the View.
Is there a standard mechanism that I can use to determine if the event is firing because of the DataContext being set versus when the user is making changes?
Thanks!
As far as I know there is no such mechanism. What you should do instead is to do your validation magic using standard means of WPF. Please see the following link: http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_validation.
Anyway, as long as you use MVVM you can always detect that text has changed in the setter of the bound property in your view model.
Related
I'm currently encountering this issue while programming Metro, but I'm sure it applies to WPF, Silverlight and possibly even WinForms.
I have a databound TextBox and a method attached to the LostFocus event of the TextBox. When it loses focus, I want the code behind to trigger a save function in order to persist the data. The problem is that the LostFocus-event triggers before the business object is updated from the GUI through TwoWay databinding.
What is the best way to handle this? Is there some way to force update of the databinding from the LostFocus method (would probably be platform-specific)?
It sounds like you're wanting to do some business logic instead of having the GUI update the textbox. I would set the Textbox to only be BindingMode.OneWay, so that when the business object is changed the textbox is updated properly.
Then in the Lostfocus event (again wpf, but I think you'll get the idea):
private void EditBoxLostFocus( object sender, KeyboardFocusChangedEventArgs e )
{
var textbox = sender as TextBox;
//update your business object w/ textbox.Text value
//other business logic
}
This way you're in full control of when the object gets updated, and can apply your business rules.
Set UpdateSourceTrigger = PropertyChanged on the TextBox binding.
http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.100).aspx
I have a command that I would like to be enabled only when a certain control has focus. I can do this with a routed command and command binding, but I'd like to keep the implementation in my ViewModel.
Is a command binding and an event handler in the code behind the only way?
To handle this within the ViewModel, you will need to add the concept of the 'certain control' having focus into your view model, enabling the command when this focus state changes.You could do this by adding a boolean IsCertainControlFocussed property to your view model.
To update this state you have two options, either handle the GotFocus and LostFocus events in the code behind of you view and set this boolean property on your view model. Or use one of the MVVM framework absraction mechanisms. For example the MVVM Light framework has an EventToCommand behaviour which allows you to wire an event to a command exposed by your view model, which could set this property.
http://geekswithblogs.net/lbugnion/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx
Which technique you use depends on how important it is to you to have no code-behind. Personally I do not follow this religiously, as long as the View Model has the right responsibilities, and is testable, a little it of code behind does no harm!
I have created a dependency property of type Binary on a RichTextBox which allows me to bind to a FlowDocument which is in binary form (byte[]) within the ViewModel. This works well, the property converts to and back correctly.
Whenever the RichTextBox looses focus then the value of the dependency property is updated with the new binary representation of the FlowDocument.
My problem is that if I have been using the RichTextBox and I close the window, the RichTextBox does not lose focus and hence the dependency property is not updated with the new binary representation of the FlowDocument and therefore new changes are not commited to the database. In my ViewModel I have a method CleanUp which gets called when a ViewModel is getting ready to be disposed, where I can save the updated document.
How can I get the dependency property to update itself as the RichTextBox doesn't lose focus if the user clicks to close the window?
I brainstormed the following:
Tell the dependency property to update itself via a message broadcast. I am not clear on how to register a message listener within the dependency property.
Query the RichTextBox directly, get the Document, convert it to a binary object manually.
Get the view to move focus to a dummy control, so that the dependency property now updates itself.
What do you guys think?
Update: the on changed event for the dependency property adds a event handler which is waiting for the RichTextBox to loose focus. It is this handler that updates the dependency with its new value.
Use an UpdateSourceTrigger of "PropertyChanged"
Something like:
{Binding Path=MyProperty,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}
I had a similar problem once, the solution I used was to move the focus to a different control and I never had any problems with this.
In my case there were several editable controls in the window so I didn't have to use a dummy control.
What's stopping you from handling the closing/closed event of the Window and moving focus or updating the binding?
I've got a WPF app who's menu is using the commanding capabilities. Everything is wired up just fine and when I click the buttons in the menu, the commands run. However I'm having trouble getting the button's IsEnabled status to respect the CanExecute part of my commands.
One challenge is the commands need to see what you're doing in the UI. For instance, one command should only be available when certain items in a ListBox are selected so I need to get a reference to the ListBox... but since the command is exposed in my view model (MVVM pattern), it doesn't have access to the UI (BTW, the menu is in one user control [parent=mainwindow] while the ListBox is in another user control [parent=mainwindow]).
In addition, even when I hard code the command's CanExecute method to return false, the Enabled property of the button doesn't change... the command won't fire, but it won't change... frustrating. I assume I need to modify/raise the CanExecuteChanged event, but I'm not sure when I should be doing that (can't find a good sample).
Feedback?
Try the Messenger class from MVVMLight. It helps in communicating between ViewModels.
And give this a try:
Have a SelectedItem property in your ListBox's ViewModel. Broadcast messages while the property changes. Register for this message in the menu's ViewModel. Use the SelectedItem property in your CanExecute method for your logic.
Normally, you would bind the Command Property of the MenuItem/Button whatever - that means you still have the CommandParameter to work with - this can then be bound to some other control. However, when the two views do not know each-other, you need som kind of mediator between them (ie. a viewmodel that both views can access - have the listbox SelectedItem/SelectedItems bound to a property two-ways - and let the CommandParameter bind to the same property one-way).
As for when to fire the CanExecuteChanged event - you should fire that whenever there is a change in the logic contained in the CanExecute-method. If it is always false, you should never fire the event, as it will read the initalvalue when the Command-parameter is set. '
If your button is behaving oddly - check to see if the IsEnabled property is influenced by Styles or set directly.
Hope this helps.
I have a "Login" button that I want to be disabled until 3 text boxes on the same WPF form are populated with text (user, password, server).
I have a backing object with a boolean property called IsLoginEnabled which returns True if and only if all 3 controls have data. However, when should I be checking this property? Should it be on the LostFocus event of each of the 3 dependent controls?
Thanks!
vg1890
I'd get the "backing object" to raise the IsLoginEnabled changed event when any of the 3 fields are updated. You can then bind the button to the IsLoginEnabled property and not have to keep checking it.
The pseudocode would look something like this:
Public Event IsLoginEnabledChanged As EventHandler
Public Property User() As String
Get.. ' snipped for brevity
Set(ByVal value As String)
mUser = value
RaiseEvent IsLoginEnabledChanged(Me, New EventArgs())
End Set
' do the same in the Set for Password() and Server() properties
The trick to this is naming the Event [PropertyName]Changed (i.e. IsLogonEnabledChanged) - because raising this event will automagically notify any bound controls :o)
Yes, I would say the easiest option would be to check it on the LostFocus or TextChanged event of each of those controls. However, if you want to do a little heavier lifting, you could implement the boolean as a dependency property that you could have bound to the button's Enable.
http://msdn.microsoft.com/en-us/library/ms750428.aspx
Can you just databind your IsLoginEnabled right to the Enabled property of the login button?
I think you could use RoutedCommands one of the most useful features of WPF. Basically add a CommandBinding, to use OnExecute and OnQueryCommandEnabled to manage button's enabled state.
Check out this wonderful explanation on using RoutedCommands in WPF