Xamarin.Forms.Datagrid Event Handler - android

Finally used Nuget Xamarin.Forms.DataGrid but know I am stuck with DataGrid.ItemSelected property.
I am using MVVM pattern with Commands, but DataGrid needs EventHandler for ItemSelected (I hope this is alternative for SelectionChangedCommand in CollectionView).
Is there way to use existing command as ItemSelected or if not how should I implement it using MVVM, main goal of command should be to update value of some IsSelected boolean value.

You can directly create binding on DataGrid.SelectedItem , and do something in Setter method .
//xaml
<dg:DataGrid SelectedItem="{Binding SelectedItem,Mode=TwoWay}"/>
//viewmodel
private object _SelectedItem;
public oibject SelectedItem
{
get
{
return SelectedItem;
}
set
{
_SelectedItem = value;
NotifyPropertyChanged();
//do something
}
}

Related

Android MVVM: databinding value is not set from MediatorLiveData in particular situation

When setting a value to MediatorLiveData that reacts to a source added in the constructor of a viewModel or activity onCreate observer in the ViewModel , like this for example:
showingMethodLiveData.addSource(stateChangeLiveData) {
when (it) {
ConfigurationState.CURRENT -> showingMethodLiveData.value = commMethod[it]
ConfigurationState.PENDING -> showingMethodLiveData.value = commMethod[it]
}
}
The value isn't set to the observing view, although the set method is called.
I can work around this by either adding the source in onStart (which creates other problems of registering observer more than once), or using postValue instead of setValue.
The debug of setValue method leads me to following code, where there is an interesting comment that tells the story, the method returns without setting the value to the binded view.
in androidx.databinding package of lifecycle dependency:
class ViewDataBinding:
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver) {
// We're in LiveData registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind();
}
}
The value is not set afterwards either, but only when the mediatorlivedata is invoked again by change in it's source.
Why this situation occurs?
Thank you for the help
PS
I think it may be an android library bug
The use of Mediatorlivedata is to compare two values and then provide a result.
If you want to change the value of a variable, you can simply use MutableLiveData and to assign a new value, write variableName.value = newValue
Should be even easier to achieve like this:
val showingMethodLiveData = Transformations.map(stateChangeLiveData) { commMethod[it] }

Android MVVM databinding set error in editext issue

According to our structure i am using MVVM architecture with databinding. Its working fine and i am creating login page. i want to set error in Editext on click of submit button so i used this code inside view model class -
public boolean isEmailAndPasswordValid(String email, String password) {
// validate email and password
if (TextUtils.isEmpty(email)) {
return false;
}
if (!CommonUtils.isEmailValid(email)) {
return false;
}
if (TextUtils.isEmpty(password)) {
return false;
}
return true;
}
now i want to set error on click of login button which id exist inside Activity class , how could i get the view id inside viewmodel class. i think it will be bad idea to pass binding object inside viewmodel class, so how could i achieve this?
You could make use of LiveData and instead of returning true or false from your isEmailAndPasswordValid method inside your viewmodel class, you could post values to the live data instead.
So instead of doing return true or return false, you do myLiveData.postValue(true) or myLiveData.postValue(false). This way, you could observe this liveData in your view and once the live data value changes you can make UI changes accordingly. For more information look at https://developer.android.com/topic/libraries/architecture/livedata
Hope it helps! :)

convert interger to decimal using databinding

I have a Integer value: 10000, which I want to databind it to the interface as 100.00.
android:text="#{BigDecimal(viewModel.transactionDetail.transaction.amount).toString()}"
Data binding is not for implementing logics inside view, it is
provided to attach view to data models.
If you use controllers / handler, you can put your converting logic there. See data binding documentation, you will always see Handlers in their examples.
Way 1
Using handler you can write your converting logic inside handler.
<variable
name="handler"
type="com.package.MainHandler"/>
android:text="#{handler.getAmountInDollar(transaction.amount)}"
In your Activity/Fragment
binding.setHandler(new Handler());
In Handler
public String getAmountInDollar(int amount) {
return new DecimalFormat("##.##").format(amount);
}
Way 2
If you don't use presenter still, you can do this.
public class Transaction {
private int amount;
public String getAmountInDollar() {
return new DecimalFormat("##.##").format(amount);
}
}
Now you can do this
android:text="#{transaction.amountInDollar}"
That's the way you should do this.

manage null boolean with RxJava2 PublishSubject

I'm implementing the MVP design pattern. My presenter receives the new values from the view. I want to manage the state of a next button by automatically check if everything is valid when values are updated on the view.
In my form I have an optional part which is displayed only if the user select the correct option.
In this optional part I have a binary question. If the part is not displayed I need to set the value of the question to null on the Presenter side.
For example, the user select the option and the optional part is displayed. The user select the answer. Then the user change the option and the optional part is hidden. In that case I need to set the answer to the optional question to null, for the answer to not be already selected if the user display the optional part again.
To do so, I call a method on the Presenter with a null value instead of true/false.
Here is the code:
private final PublishSubject<Boolean> mObsOptionalAnswer = PublishSubject.create();
public MyPresenter(){
// Combine all the values together to enable/disable the next button
Observable.combineLatest(
// ... other fields
// I need this to return false if the optional part is
// displayed but nothing is selected
mObsOptionalAnswer.map(this::isValid),
(...) -> ...
).subscrible(enable ->{
mView.enableBtn(enable);
});
}
public void myFunction(Boolean isSomething){
// ... some code
mObsOptionalAnswer.onNext(isSomething);
}
private boolean isValid(Boolean value){
return value != null;
}
The problem is, since RxJava 2, null values are not allowed in the onNext() method.
So, how am I supposed to manage that?
If you want to be able to send a null value, you can use a wrapper. In this configuration, you send the wrapper, which isn't null even if the value itself is.
public class BooleanWrapper {
public final Boolean value;
public BooleanWrapper(Boolean value) {
this.value = value;
}
}
Your PublishSubject<Boolean> becomes a PublishSubject<BooleanWrapper> and you just have to create the wrapper and de-reference your Boolean when needed :
mObsOptionalAnswer.onNext(new BooleanWrapper(isSomething));
and
mObsOptionalAnswer.map(wrapper -> this.isValid(wrapper.value))
If you need to do that more than once in your code, you can create a generic wrapper (as described by this tutorial) :
public class Optional<M> {
private final M optional;
public Optional(#Nullable M optional) {
this.optional = optional;
}
public boolean isEmpty() {
return this.optional == null;
}
public M get() {
return optional;
}
}
you could use a constante Boolean object
public static final Boolean RESET_VALUE = new Boolean(false);
and you can emit this instead of emitting null. The receiver would have to check against this instance and behaving accordingly. Eg.
.subscrible(enable ->{
if (enable != RESET_VALUE) {
mView.enableBtn(enable);
}
});

Search from List which is in ViewModel (Xamarin Android )

I am new to Xamarin Android Development and I am using MvvmCross for binding data.I have SerachView on action-bar.I want to search data from list which is in ViewModel.How can I implement that ? I have searched for this issue on internet but all have used adapter and i want to search list-item without using adapter from ViewModel.I am not getting any idea how to do that.So anyone can suggest me an easy way?
Any suggestion or advice will be appreciated.
It is pretty simple.
Your SearchView is bound to a string property which you are using for filtering. Here I assume it is called SearchQuery.
It is not clear what criteria you want to use for filtering, I will assume that the ViewModel has a Name property, where the SearchQuery will be contained in that name.
So your ViewModel would look something like:
public class SearchViewModel : MvxViewModel
{
public string SearchQuery
{
get { return _searchQuery; }
set {
_searchQuery = value;
RaisePropertyChanged(() => SearchQuery);
RaisePropertyChanged(() => FilteredResults);
}
}
public List<ListItemViewModel> UnfilteredResults
{
get { return _unfilteredResults; }
set {
_unfilteredResults = value;
RaisePropertyChanged(() => UnfilteredResults);
RaisePropertyChanged(() => FilteredResults);
}
}
public List<ListItemViewModel> FilteredResults
{
get
{
if (string.IsNullOrEmpty(SearchQuery))
return UnfilteredResults;
return UnfilteredResults
.Where(r => r.Name.Contains(SearchQuery)).ToList();
}
}
}
So what happens is, whenever you enter a new value into the search box, it will trigger the PropertyChanged event on FilteredResults and use a simple LINQ query to filter the results.
If you don't want to swap out the entire list every time, you can do this with an ObservableCollection and add and remove items in that instead.
EDIT:
So as stated above you just bind the MvxListView to the new items source. Assuming you are using a AXML layout for your view:
<MvxListView
..
local:MvxBind="ItemsSource FilteredResults; ItemClick ResultClickedCommand" />
As for the SearchView, I just looked, there does not seem to be any code in MvvmCross to easily bind to that, and it does not inherit from EditText, so you need to do something like described here: https://stackoverflow.com/a/22501906/368379
Easiest way is probably simply to implement the SearchView.IOnQueryTextListener interface and in there set the new string you receive in the implementation on your ViewModel.

Categories

Resources