I have a little question:
In my axml Designer I have something like this:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="{'Text':{'Path':'FirstName'}}" />
That works fine, but how could I combine/concat 2 Properties (or even more)..
So something like: FirstName + SecondName (2 Properties in one Text)
This is a standard Mvvm question. I think it came up a lot in the early years of Wpf - I think there are lots of ideas around about multiple dependencies.... I've not implemented any of these yet...
If you want to do this, then you could use:
(1) expose a combination property on the ViewModel object:
public string FullName
{
get
{
return FirstName + SecondName;
}
}
if you do this, then you'll need to make sure that when you RaisePropertyChanged("FirstName") or RaisePropertyChanged("SecondName"), then you also RaisePropertyChanged("FullName")
(2) Use a converter to combine the names together:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="{'Text':{'Path':'','Converter':'MakeFullName'}}" />
Note that the Converter here takes the parent object as its input parameter.
Note that in this case, if FirstName or SecondName change then the text view might not get updated :/
(3) You could use multiple TextViews in the UI - each one bound to the necessary bit of text.
(4) You could use a single textview and use C# level binding - e.g. in the View use code like:
ViewModel.PropertyChanged += (s,e) => {
if (e.PropertyName == "FirstName" || e.PropertyName == "SecondName")
{
this.FindViewById<TextView>(Resource.Id.XXX).Text = ViewModel.FirstName + ViewModel.SecondName;
}
}
If you think multi-dependency bindings are an important requirement, please log this as an issue (feature request) in https://github.com/slodge/MvvmCross/issues - or maybe even just fork the code and add them :)
Related
I am trying to learn about Xamarin Android and I have some dubts.
I have a layoout, my .xaml file and my .cs file (I am not sure if this could be considerate my view model in the same way than in the WPF applications).
In my layout I have this:
<TextView
android:text="txtDireccionServicio"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/txtDireccionServicio" />
but in the text I have a warning that tell me that is is a hardcode value, that I should to use a #string resource.
Well, I have in my .cs file this property:
private string txtDireccionServicio = "Prueba";
But I don't know how to use this propery in my layout. I have tried this:
android:text="#txtDireccionServicio"
But it shows "#txtDireccionServicio". But in this case the layout doesn't warn that it is a hardcode value.
So my question is, how could I bind the Text property of the TextView with the string property in my .cs file?
Thanks.
Android doesn't support Data-Binding in default . So we need to set the text by using Element.Property=xxx
In your activity
TextView tx = FindViewById<TextView>(Resource.Id.txtDireccionServicio);
tx.Text = "xxx";
Note:
We need to invoke the line tx.Text = "xxx"; if we change the value of text in runtime .
I am working on an application that is Xamarin Native using MvvmCross. I have spent the afternoon looking for an example of how to bind a list of strings to a table view in iOS but every example is binding to a List of Models and not string. I know this can be done in android...
<Mvx.MvxListView android:id="#+id/lvErrors"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/lblCaption"
android:layout_alignParentLeft="true"
local:MvxBind="ItemsSource Errors" />
where "Errors" is a List of strings. However trying a similar approach in iOS fails to load data.
var set = this.CreateBindingSet<ViolationDetailsView, ViolationDetailsViewModel>();
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText Errors;");
ErrorsTableView.Source = source;
set.Bind(source).To(vm => vm.Errors);
set.Apply();
Can anyone point me in the right direction to find an example of this?
I ended up finding the answer here. "If you want to bind to the whole string object then use a . period for whole object binding."
So...
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText Errors;");
became...
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText .;");
I knew it was something simple.
I currently use ZK for web-development. Here is my case:
I implement instant search, once text change=> perform search.
Zul File
<textbox id="textSearch" sclass="search_text">
<attribute name="onChanging">
lbOnChangingSearch.setValue(event.getValue());
vm.onChangingTextSearch();
</attribute>
</textbox>
<label id="lbOnChangingSearch" visible="false"></label>
<grid id="gridChapter" model="#load(vm.chapterInPage)">
....
</grid>
Controller code
ListModelList<ChapterJoinComic> chapterInPage;
public ListModelList<ChapterJoinComic> getChapterInPage() {
return chapterInPage;
}
#NotifyChange({ "topComics", "chapterInPage"} )
#Command
public void onChangingTextSearch() {
FilterObject fo = getFilterObject();
fo.setSearch_str(lbOnChangingSearch.getValue());
//
doSearch(fo); // Change chapterInPage
// Manually post Not
BindUtils.postNotifyChange(null,null,this.chapterInPage,"chapterInPage");
}
Problem
After call onChangingText search, Grid dont update databinding.
But if I continue change text (more call onChangingTextSearch ). The Grid will update, but the updated value is the previous value.
It seems the Grid is a-step slower than my latest Model object.
Note If I use onOK instead of onChanging event, the databinding works well.
Anyone can help me. Thanks in advance!
In addition of Malte his answer.
Textbox only sends data to the server with the onChange event to avoid needless network traffic.
If you want to send data to the server with the onChanging event, you need to do :
<textbox instant="true" />
In this case the client will update almost instantly to the server (if you type fast, it will be when you stop typing)
You should remove the BindUtils.postnotifyChange when you use #NotifyChange already, and you use it wrong anyway: the third parameter should be this instead of this.chapterInPage. The JavaDoc explains that you need to specify the bean whose property is changing and the name of the property.
Furthermore, replace your onChanging attribute with the proper way to call a command:
<textbox id="textSearch" sclass="search_text"
onChanging="#command('onChangingTextSearch')" />
Consult the documentation for more information on how to use commands. I think because you do not use the command as a command, the #NotifyChange is not triggered. And your postNotifyChange is wrong, as I said.
Let me know if that works or if there are other problems remaining.
EDIT
I just re-created an example on my own, and it seems to work. Try it like this:
ViewModel --------------------------------
private String searchText = "";
#NotifyChange({"chapterInPage", "searchText"})
#Command
public void onChangingTextSearch(#BindingParam("text") String searchText)
{
this.searchText = searchText;
}
public String getSearchText()
{
return searchText;
}
public ListModelList<String> getChapterInPage()
{
return new ListModelList<>(searchText.split(""));
}
zul --------------------------------------
<textbox onChanging="#command('onChangingTextSearch', text=event.value)" />
<label id="lbl" value="#load(model.searchText)" />
<listbox model="#load(model.chapterInPage)" />
Note that I use command binding to call the search method in the model instead of calling it "manually" in an onChanging listener. This way, I actually execute it as a command, which triggers the notifyChange. When you call it like vm.onChangingTextSearch() in a listener, the #NotifyChange is ignored.
This way, it works as expected, and with every character typed (well, after a couple of millisenconds delay), the list updates. Another advantage is that you do not have to bind your label into the view model, something that zk's documentation discourages.
Can you try to link your zul and model like this and tell me if it works. If it doesn't, you might want to try to create an example on zkFiddle that re-produces your code's behavior.
I'm using MvvmCross 3.0.14 with Xamarin.Android.
I have an MvxImageView that I can get to display a particular local graphics resource if I specify the image directly (without binding) using android:src:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
android:src="#drawable/Card_kh"/>
But I can't get the same image to show up using local:MvxBind:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl 'res:Card_kh'"/>
This does not work. MvxAndroidLocalFileImageLoader.LoadResourceBitmap logs a trace message indicating that 'Card_kh' was not a known drawable name. It's encouraging that it got that far -- at least I know that the intended consumer of this information did get it. But apparently I have not provided that information in the correct format.
Taking it one step further, my actual goal is to have my ViewModel determine what resource should be used, e.g.
class MyViewModel : MvxViewModel
{
public string SomeImagePath { get { return "res:Card_kh"; } }
}
and
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl SomeImagePath"/>
What do I need to do to have an MvxImageView bind to a view-model determined local resource image?
The problem was only capitalization in the resource name. Although the image filename starts with a capital C, and the android:src attribute works with a capital C, the MvxBind of ImageUrl requires a lowercase c:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl 'res:card_kh'"/>
This also solves the problem when the source of the ImageUrl value is a viewmodel property:
class MyViewModel : MvxViewModel
{
public string SomeImagePath { get { return "res:card_kh"; } }
}
and
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl SomeImagePath"/>
The previous answer is not working anymore since MVVMCross v6.0.0.
As described here https://www.mvvmcross.com/documentation/upgrading/upgrade-to-mvvmcross-60 MvxImageView has been removed from the API.
The newest alternative is now https://github.com/luberda-molinet/FFImageLoading/wiki/MvvmCross.
This nuget package "Xamarin.FFImageLoading" must be added in order to make the code below work.
<ffimageloading.cross.MvxCachedImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImagePath SomeImagePath"/>
When I'm binding text to an input on iOS, my setter is called each time a character is added, on iOS, but not on Android.
If I put a breakpoint on a property that is binded to a TextField in iOS, each time a character is entered, the property setter will be called, but not on an Android EditText.
It makes more complex ViewModels with several input attached to getter/setter tested on iOS completely useless on Android since it cannot be used.
Is there a way to make the "MvxBind="Text SomeProperty" acting like iOS on Android?
Events like "AfterTextChanged" (any binding to a command) aren't property-friendly, and would break my ViewModel. I don't want to have a platform-dependent workaround.
[Edit]
// Droid. It calls the TotalAmount setter once the editing is done.
<EditText local:MvxBind="Text TotalAmount,
Mode=OneWayToSource; Text TotalAmountString, Mode=OneWay" />
// Touch. It calls the TotalAmount setter on key press.
set.Bind(MyTotalAmountTextField)
.For(v => v.Text)
.To(vm => vm.TotalAmount).OneWayToSource();
set.Bind(MyTotalAmountTextField)
.For(v => v.Text)
.To(vm => vm.TotalAmountString).OneWay();
By the way, the displayed property is always formatted with a dollar sign, that's why I'm using an half-duplex approach for binding.
Appart from this live (iOS) versus after-edit (Droid) problem, the bindings are working well.
The default behaviour for TwoWay Text binding on both Android and iOS is to do per character binding.
You can see this behaviour in, for example, the N=0 video at 18:43 - http://youtu.be/_DHDMNB_IeY?t=18m43s
If you are not seeing this behaviour in your EditText then I guess it might be down in some way to your app or perhaps to a bug (e.g. perhaps in OneWayToSource binding somehow - this certainly isn't as commonly used as other binding modes).
To workaround this, I can only think to suggest:
Log it as an issue with a reproducible case (github repo) on GitHub/MvvmCross - someone there might be able to help - or you might be able to fix it yourself.
Try TwoWay binding instead
Try creating your own custom binding or your own custom control - this is actually very easy to do - see the tutorials N=28 and n=18 on http://mvvmcross.blogspot.com - for example you could try inheriting from EditText to create something like;
public class MyEditText : EditText {
public MyEditText(Context c, IAttributeSet a) {
this.AfterTextChanged += (s,e) => MyTextChanged.Raise(this);
}
public event EventHandler MyTextChanged;
public string MyText {
get { return Text; }
set { Text = value; }
}
}