Error handling for AutoCompleteBox with Silverlight 3 + MVVM Light toolkit - silverlight

I'm trying to create a UserControl that contains a AutoCompleteBox. I want to use the SelectedItem property of this AutoCompleteBox to populate other UserControls with information based on which item the User selected.
To prevent the SelectedItem to be fired every time a user "navigate" between items in the drop-down I've created a EventToCommand that executes on DropDownClosed event like this:
The command is of type:
public RelayCommand SelectedItemCommand { get; private set; }
This works fine except for when a user start typing something that has a match at the beginning, but if the user continue typing and there is no match anymore, then the DropDown is closed and no item is actually selected. This gives me an error that says:
Unable to cast object of type 'System.Windows.RoutedPropertyChangedEventArgs`1[System.Boolean]' to type 'MyProject.ViewModels.MyItem'
I tried to make a try-catch statement in the Command method for the command, but the exception seems to be fired even before I get into that method.
My question is:
How can I prevent the command from beeing fired if there is no-match (that is, no actual SelectedItem in the AutoCompleteBox)?

Are you using PassEventArgsToCommand? In that case, the RelayCommand must be RelayCommand<EventArgs> and the CommandParameter may not be used. It is a limitation of the ICommand interface, which can only have one CommandParameter. Annoying, I know, but usually I am able to use a different way to get what I want (for example by binding the SelectedItem to a property on my VM with a TwoWay binding).
Let me know,
Laurent

Related

WPF: MVVM - Disable command attached button on ivalueconverter convert exception

I have a simple scenario and a issue with it which I just cant seem to resolve past few days.
OK, first of all I use MVVM to bind my View on a ViewModel. I have in my view several text boxes which binds to several properties (most strings) in ViewModel (binds actually to an Custom Object (type Person, name SelectedPerson) with strings properties , object which is a property of the viewmodel). This object implements INotifyPropertyChanged and IDataErrorInfo. It has also an int property named Age. I also have in my view a button which is bound to a command in my viewmodel, a command which inside CanExecute test the SelectedPerson's properties and return true if all are correct.
Now my issue is: if I put in my Age text box from my View something not int, a red tectagle will appear (is normal, because there is an exception to the conversion), but in that specific moment, to the object behind (SelectedPerson, type Person) there isn't sent the newValue (the setter to that property Age, or the IDataErrorInfo Members don't intercept the value .... I guess it is normal because there isn't any "new" value, because I put an incorrect format in the text box in the first place).
So, maybe I repeat myself, the issue is: if the new Age (new incorrect Age) isn't set, then the Object behind still hold last value, which if it was correct then the command itself it's correct (the can execute will return true) and the button is enabled
As you can imagine I want the submit button (it's a button which saves current person details in data storage module) to be disabled when current properties don't pass through conversions methods.
PS: I used a IValueConverter class , and on that text box binded to Age, I made use of my StringToIntConverter class....but on Convert Method I don't know how to pass the SelectedPerson binded object (I just pass the text value, and return the int value)
I guess one way to do it could be by using MultiBinding scenario , but I'm not sure.
If I could pass the SelectedPerson inside Convert method from that converter I could invalidate that command from the converter itself.
Sorry for my English, I know it's far from perfect :) and thanks in advance for your time.
I think the cleanest solution would be to bind the textbox to a string property instead, and update your view model so that your IDataErrorInfo implementation for that property name attempts a string to int conversion and returns the result of that. Your CanExecute test would also then include this conversion as part of the validation test.

Accessing controls from within commands in WPF

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.

DataContext, DataBinding and Element Binding in Silverlight

I'm having one hell of a time trying to get my databinding to work correctly. I have reason to believe that what I'm trying to accomplish can't be done, but we'll see what answers I get.
I've got a UserControl. This UserControl contains nothing more than a button. Now within the code behind, I've got a property name IsBookmarked. When IsBookmarked is set, code is run that animates the look of the button. The idea is that you click the button and it visually changes. We'll call this UserControl a Bookmark control.
Now I have another control, which we'll call the FormControl. My FormControl contains a child Bookmark control. I've tried to do databinding on my Bookmark control, but it's not working. Here's some code to help you out.
This is the XAML and Loaded event handler of my control. As you can see it contains a child element that is a custom control (bookmark). So once this control loads, it's DataContext is set to an new instance of an Employee object. Silverlight also sets the DataContext property of my child bookmark control to the same instance. I've verified this by debugging. If my parent has a valid DataContext set then why can't my child control (bookmark) property databind to it?
<UserControl ......>
<q:Bookmark x:Name="BookMarkControl1" IsBookmarked="{Binding IsSiteBookmarked}" />
</UserControl>
public void Control_Loaded(object sender, EventArgs e)
{
DataContext = new Employee { IsSiteBookmarked = True };
}
This is my custom control below. Obviously it contains more than this, but for readability I've trimmed it down to the property I'm trying to databind to.
//this is the bookmark control. I've included this control within another control, and I'm trying to databind to properties within my parents DataContext
public partial class Bookmark : UserControl
{
bool _IsBookmarked= false;
public bool IsBookmarked
{
get {return _IsBookmarked;}
set {
_IsBookmarked= value;
SwitchMode(value);
}
}
}
UPDATE
Got some javascript errors that I should mention. Firebug reports a AG_E_PARSER_BAD_PROPERTY_VALUE exception. It doesn't seem like my databinding is even working yet.
Make your IsBookmarked property on the Bookmark control a dependency property.
I presume Control_Loaded is a part of your FormControl, in which case I'm not sure you are using DataContext properly. Best double check that.
UPDATE: Yes, you are using the DataContext properly. AG_E_PARSER_BAD_PROPERTY_VALUE indicates you need to make the IsBookmarked property a dependency property, like so:
Public Property IsBookmarked() As Boolean
Get
Return Me.GetValue(IsBookmarkedProperty)
End Get
Set(ByVal value As Boolean)
Me.SetValue(IsBookmarkedProperty, value)
End Set
End Property
Public Shared ReadOnly IsBookmarkedProperty As DependencyProperty = DependencyProperty.Register("IsBookmarked", GetType(Boolean), GetType(Bookmark), New PropertyMetadata(New PropertyChangedCallback(AddressOf OnIsBookmarkedPropertyChanged)))
Private Shared Sub OnIsBookmarkedPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim cntrl As Bookmark = TryCast(d, Bookmark)
cntrl.SetIsBookmarked(e.NewValue)
End Sub
If you only need to store the value for later use, then you don't need to do anything in the OnIsBookmarkedPropertyChanged procedure, But I put some code there as an example anyway.
Good Luck!
I don't recall the exact order in which databinding is evaluated (and I'm too lazy to go look it up), but as I recall, it initially happens BEFORE the form's Loaded event fires, and without making the IsBookmarked property a dependency property, or at least using INotifyPropertyChanged, it may have trouble establishing the datacontext appropriately. I'd recommend either implementing INotifyPropertyChanged or making IsBookmarked a dependency property. DataBinding is tough enough to get right in the best of circumstances (see my long, bad-tempered rant about it here), and you'll just be making it more difficult on yourself if you aren't setting up your properties in the way that it expects.
The control exposes a IsSiteBookmarked property(which I believe should be a DependencyProperty) but the control is binding to a IsBookmarked which is not shown. Is this intentional? Have you checked your Visual Studio output window for binding errors?
Addition 1:
Since you have fixed the typo in your question and added that there is an error being reported.
Start by clearing up the AG_E_PARSER_BAD_PROPERTY_VALUE problem. Is there a line number and start position in the error message? Start looking there. One strategy is to start taking out XAML until there is no longer an error. This will narrow down the offending code.
Running in debug, mode check for binding errors in the output window.
You might want to also post the Employee class code, especially the IsSiteBookmarked property.
Typically when doing databinding to an object you will want to leverage the INotifyPropertyChanged interface and implement that so that the control can properly invalidate it's property value. Unless you use INotifyPropertyChanged with Mode=TwoWay then any code that changes your DataContext's IsSiteBookmarked will have no effect.

Silverlight MVVM binding seems not to work

Building my first SL MVVM application (Silverlight4 RC) and have some issues i don't understand.
Having a WPF background i don't know what is going on here:
ViewModel has several properties, in which one is called SelectedRecord. This is a get only property and is defined like this:
public Culture SelectedRecord {
get { return culturesView.View.CurrentItem as Culture; } }
As you can see it is gets the current value of a CollectionViewSource (called culturesView). So if i select a Culture, the SelectedRecord (gets a value directly from within the CollectionViewSource) as expected. (Actually there is a datagrid control bound to the CollectionViewSource, hence it is possible to change the selected item)
OK. Now to the View . There are several views which access this ViewModel and in particular there is one which shows the values of the aforementioned property SelectedRecord (let's call it the EditView). To show this EditView there is a button (which has its Command property bound to an ICommand in the ViewModel) which functions (the first time) as expected.
This means:
1st try : i select a record, switch to EditView, outcome: selected record values are shown (as expected!!).
2nd try: switch back to datagrid, select another record, switch to EditView, outcome: the values of the previous shown record are shown again!!! WHY??
First i thought that the SelectedRecord has not the correct value set, but i was mistaken: it HAS the correct value! So it should be shown!?
What am i missing? In WPF this would work!!
Thanks in advance
When CurrentItem value changes, your ViewModel that has SelectedRecord must call RaisePropertyChanged("SelectedRecord") so whatever View is bound to it is notified about the change.

How To access commands on usercontrol from viewmodel

I have legacy windows forms user control that exposses several public methods. I wrapped this control on a wpf user control and encapsulated the Methods with a relaycommand on the new wpf usercontrol.
Now my problem is how to use the mvvm pattern to execute the commands on my user control form the viewmodel that is used with the view hosting the new wpf usercontrol.
In viewmodel you have to add a field say
Public ICommand CommandOne
Now this command will create a new RelayCommand object depending upon your requirements/conditions.
Now, you can bind this 'CommandOne' command with any object say button on your control form.
So, whenever the button is clicked then the RelayCommand object will be created and it will execute the action given to it as a parameter.
Hope it works for you.
I Fond out how to get this to work with bindings. Need to set the mode to OneWayToSource to get the command from the user control. The tricky part is that the initialization of the command has to be done inside the loaded event of the usercontrol. If you try to do it inside of the constructor, you will end up with the default initialization from the binding which could be null.
Use PRISM EventAggregator? You can fireoff an event from ViewModel, from your Usercontrol subscribe to it.
http://www.codeproject.com/Articles/355473/Prism-EventAggregator-Sample
https://msdn.microsoft.com/en-us/library/ff921122.aspx

Resources