Using MVVMCross to bind to error messages - xamarin.ios

I am new to MVVMCross (and mobile in general) and I am looking to implement binding to error messages (like FluentValidation ValidationResults or IDataErrorInfo).
Preferably, I would like an Errors like dictionary that I can bind directly to:
bind(label).To(vm => vm.Errors["Name"])
I have tried an ObservableDictionary (http://blogs.microsoft.co.il/blogs/shimmy/archive/2010/12/26/observabledictionary-lt-tkey-tvalue-gt-c.aspx), but I am not getting notified when the ViewModel adds errors.
As expected, wrapping access as a property in the view model works, but could get cumbersome:
public string NameError { get { return Errors.ContainsKey("Name") ? Errors["Name"] : null; } }
I have also considered creating a custom binding, but am not sure how to get access to the ViewModel and pass the field name I want. Seems like I could pass Errors or the property name.
Finally, since invalid conversions (i,e. 22ab for an int) are not pushed down into the view model, is there a way to get those errors? Should I be validating before data gets pushed back to the view model instead? Like textFieldShouldEndEditing or ShouldChangeCharacters on iOS? I could wrap a custom control if necessary.
What techniques are others using with Xamarin/MVVMCross using to provide validation feedback?
Thanks in advance.

MvvmCross doesn't currently implement the IDataErrorInfo level of data-binding
This is mainly because no-one has yet asked for it - but I guess that might just change with this question. If you do have specific requirements, then the project would be interested to hear them - suspect the best place for that is github issues for the project.
For your specific questions...
The approach of binding to an ObservableDictionary which implements the INotifyCollectionChanged and INotifyPropertyChanged should work.
However, looking at the code in your link, I don't think that dictionary is correctly implementing INotifyPropertyChanged - in addition to the INotifyCollectionChanged events, it should also be raising the property change notifications on Count and Item[] - without these the binding to the whole set will work, but not to individual items and to count. For an example source of ObservableCollection, see https://github.com/mosa/Mono-Class-Libraries/blob/master/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs
Looking a second time at the code in your link, it appears that the dictionary is correctly implementing INotifyPropertyChanged - it is raising the property change notifications Item[] - and this is the string required for the individual items to bind. Do you have debug trace enabled? Does the trace give you any clue about why it is failing?
I've submitted some fixes today - https://github.com/slodge/MvvmCross/issues/345 - and have tested them in this sample - Test_WithErrors.axml - I would expect this same sample should work on iOS (the iOS test app is a work in progress) and that it should also be extensible for Jeremy's excellent FluentValidation (although I've not used that in PCL form yet)
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email:"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="30dp"
local:MvxBind="Text Email"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#ff0000"
local:MvxBind="Text Errors['Email']"
/>
Thanks for pointing out this error - fixed binaries will be nuget in the next day or two!
On the int-string question, the binding layer currently "does it's best" (TM) to convert UI types to VM types. However, there is no event currently triggered when it fails - so there is no way to fire any validation rules in the ViewModel from the binding.
Instead, where free text input is allowed, I think you'll need to implement the ViewModel types as string and will then need to trigger the validation rules when the ViewModel property changes. Because MvvmCross doesn't expose any binding level hooks for when validation occurs, you'll maybe need to tweak when binding occurs (e.g. on first responder resign) rather than having continual validation - but this should be fairly straight-forward using a custom-binding.

Related

"Unresolved reference: userRecyclerView"

userRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/userRecyclerView"/>
I saw a code tutorial video. When he used "userRecyclerview", it says "userRecyclerview" comes from the second code I post above. But it did not come out when I write "userRecyclerview", also there is a Unresolved reference problem.
Seems like they're using Kotlin synthetics to bind the view.
Kotlin synthetics will generate some extra code that will allow you to access views in the layout XML, just as if they were properties with the name of the id you used in the layout definition.
But it has been deprecated already. So to access your views either use findViewById() or replace Kotlin synthetics
with Jetpack view binding following this: https://developer.android.com/topic/libraries/view-binding/migration

How to get rid of the warning "cannot resolve symbole 'id/andr'" for ExpandableListView"

An app uses ExpandableListActivity, and the usage of ExpandableListView is standard based on the document:
<ExpandableListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:divider="#android:color/transparent"
android:dividerHeight="5dip"
android:layout_marginTop="10dip">
</ExpandableListView>
Android Studio 3.2 has the following warning:
How can I get rid of the warning?
This is probably a typo. Change it to:
"#android:id/empty"
and
"#android:id/list"
See also https://developer.android.com/reference/android/app/ListActivity
ListActivity has a default layout that consists of a single,
full-screen list in the center of the screen. However, if you desire,
you can customize the screen layout by setting your own view layout
with setContentView() in onCreate(). To do this, your own view MUST
contain a ListView object with the id "#android:id/list" (or R.id.list
if it's in code)
I don't know what is ( id="#id/android:list")
give it an normal id ( #+id/androidlist )
and handle it in your code
but if you learn how to work with ExpandableListView
I prefer this link tutorial for you ExpandableListView Link
GL sir

MvvmCross indexed property bind not getting changes from view

I have a list on my view model that contains an object and property that I am trying to bind to from the main view.
var field = new UITextField();
Add(field);
this.AddBindings(
new Dictionary<object, string>()
{
{ field, "Text Names[0].Value" }
}
);
This will load fine and display the initial value from the view model but won't receive any values back when UITextField.Text is modified. It seems like it is not 2 way. Value is not a notification property but could be made into one if that is what this setup requires.
I also tried the following but that does work at all:
set.Bind(field).To(vm => vm.Names[0].Value);
Using MvvmCross 3.0.9. Xamarin.iOS 6.3.7
I've just tested this using 3.0.9 with a ViewModel which has an ObservableCollection of non-INPC Thing objects and this two way binding seems to work OK for me - both when the ObservableCollection changes and when the UITextField value changes because of user action.
Can you provide any more of your ViewModel nad list object code? (If not, can you reproduce the error in a simple sample?)
Can you provide any error trace you are seeing (in debug|output)? (This may need enabling - see MvvmCross Mvx.Trace usage)
Can you provide any more information on the form that "does work at all" - this might be a clue about what is going wrong.

Android "tools" namespace in layout xml documentation

Per the question here,
What's "tools:context" in Android layout files?
The 'tools' namespace reference (xmlns:tools="http://schemas.android.com/tools") has begun to appear in my layouts recently, and I want to know more. The original post only described the 'tools:context' attribute, but I have also noticed usage of the "tools:listitem" attribute appearing when I have designated a preview layout item for a listview, i.e.
<ListView
android:id="#+id/lvCustomer"
tools:listitem="#layout/customer_list_item" >
</ListView>
Are there more elements?
What brought me to this 'tools' namespace is that I want to be able to have 'preview-only' text (i.e. in a TextView or EditText) when using the layout designer in eclipse.
Currently, I assign the 'text' or 'hint' property for previewing text when arranging my layouts... but then I always have to remember to clear the preview value from within the code.
Ideally, instead of
<string name="preview_customer_name">Billy Bob's Roadhouse Pub</string>
...
<TextView
android:id="#+id/tvCustomerName"
android:text="#string/preview_customer_name"
</TextView>
have a something like:
<TextView
android:id="#+id/tvCustomerName"
tools:previewText="#string/preview_customer_name"
</TextView>
Thanks-
We've just added support for designtime attributes like this in Android Studio 0.2.11. See http://tools.android.com/tips/layout-designtime-attributes for more.
Think of them as design time helpers only.They do not get processed in actual view rendering at run time.
For example you want to set background of some view in your layout design when working on android studio so that you can make clear distinction where that particular view is.So you would normally do that with
android:background="#color/<some-color>"
Now risk is that sometimes we forget to remove that color and it gets shipped in apk.
instead you can do as follows:
tools:background="#color/<some-color>"
These changes will be local to android studio and will never get transferred to apk.
And also check out http://tools.android.com/tech-docs/tools-attributes for more options.
You will find tool attribute when you set object in graphical layout.
Listview (in graphical mode) -> right Click -> Preview List Content -> Choose Layout...
produces:
tools:listitem="#layout/customer_list_item"
See in layout XML below. There are 2 namespace in use "xmlns:android" and "xmlns:tools".
Tools namespace is used when the developer wants to define placeholder content that is only used in preview or in design time. Tools namespace is removed when we compiled the app.
So in the code below, I want to show the placeholder image (image_empty) that will only be visible at design time, and image1 will the actual image that will be shown when the application launch

Alerts or Popups in MvvmCross

Does MvvmCross support a cross platform solution for displaying alerts or popups?
Searching the code I found MvxDialogActivityView but it has been commented out. Will this remain the case for now?
If there is no direct support how would you suggest this is best done? (Perhaps the ViewModel would change a property and call FirePropertyChanged so that the View would be aware of it and show an alert.)
Edit 16:04 16th June 2012
What I am trying to do for this specific case is as follows:
On the page a button is clicked, which causes a method to run in the ViewModel which does an evaluation to determine which of two messages should be shown to the customer. The message would be shown as an alert or popup (either native, or preferably totally styled by me). The message would fade after (the click of the OK button, or preferably 3 seconds).
After the message has been dismissed a new page will be navigated too (depending on which of the two messages was shown).
How to handle this definitely depends on what the situation is - there's no single best rule (IMHO)
For a general error display pattern, there's one proposal at http://slodge.blogspot.co.uk/2012/05/one-pattern-for-error-handling-in.html
I've used similar patterns for showing application level notifications - e.g. for when a long running operation completes or when a chat message arrives or...
One interesting post about how to display message boxes was: http://awkwardcoder.blogspot.co.uk/2012/03/showing-message-box-from-viewmodel-in.html - I'm not sure I'd completely follow the end solution, but there are definitely some good points there about what not to do.
For your updated scenario, I would consider using a messenger (like TinyMessenger) or using normal C# events exposed by the ViewModel and consumed by its View
On the page a button is clicked, which causes a method to run in the ViewModel
I would implement this using an ICommand bound to the button Click/Tap/TouchDown
which does an evaluation to determine which of two messages should be shown to the customer.
I would definitely implement the logic within a Service
This would be called from the ViewModel - and the result/decision would probably cause some property or private field state change.
How does the View then decide to show a message? I can think of 3 options:
The View could just respond to a Property change (normal Mvvm INPC) - this would be my preference
The ViewModel could expose a normal C# event which it triggers...
The ViewModel could send a Message
This last option (Messenging) is probably the most flexible solution here - it decouples the View and ViewModel in case you later decide to change responsibilities. To implement messenging, either:
implement your own hub (like I do for errors in http://slodge.blogspot.co.uk/2012/05/one-pattern-for-error-handling-in.html)
or use a generic solution like TinyMessenger
The message would be shown as an alert or popup (either native, or preferably totally styled by me).
This is a View concern - so would be entirely controlled by the View project. I'd use controls like: UIAlert, Toast, ToastPrompt, etc - all of which can be styled
The message would fade after (the click of the OK button, or preferably 3 seconds). After the message has been dismissed...
I'd use some form of Code Behind (or maybe a Behaviour in WP7) in the View. This would detect the click/fade/disappear and would then invoke either an ICommand (my preference) or public method on the ViewModel
a new page will be navigated too
This navigation would be requested from the ViewModel
(depending on which of the two messages was shown).
This would be easy to track through the above flow... presumably the ViewModel already knows what to show.
So that's what I'd do...
it keeps the application flow logic inside the ViewModels (and lower)
it keeps the presentation inside the Views
...but I'm sure there are other options :)
One final note... the fade out and then navigate logic can really get "messed up" by Switching/Tombstoning on WP7 and Android - this may or may not matter for your particular scenario.

Resources