Reputation: 16813
I have the following recyclerview
where it contains list of TestViewModel
objects. In this object I have age
, gender
and name
properties. I am trying to achieve when user click on a list item, it takes user to detail view where user could able to update and click on the save button, then it updates the selected item properties.
Issue:
The following piece of code in MainViewModel
where I receive the message from DetailViewModel
works when user enter values in the detail and updating each property,
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age = obj.messageTest.Age;
_selectedItem.Name = obj.messageTest.Name;
_selectedItem.Gender = obj.messageTest.Gender;
}
but the following piece of code does not work where I am trying to update the object by itself directly.
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}
Code Implementation is as follows:
<MvxRecyclerView
android:id="@+id/TestRecyclerView"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
local:MvxBind="ItemsSource TestsViews; ; ItemClick ItemSelected" />
MainViewModel
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ShowViewModel<DetailViewModel>(
new DetailViewModel.Parameter
{
Age = _selectedItem.Age,
Name = _selectedItem.Name,
Gender = _selectedItem.Gender,
});
RaisePropertyChanged(() => SelectedItem);
}
}
public virtual ICommand ItemSelected
{
get
{
return new MvxCommand<TestViewModel>(item =>
{
SelectedItem = item;
});
}
}
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age= obj.messageTest.Age;
_selectedItem.Name= obj.messageTest.Name;
_selectedItem.Gender= obj.messageTest.Gender;
}
TestMessage
public class TestMessage : MvxMessage
{
public MainModel messageTest { get; set; }
public TestMessage(object sender, MainModel editTest) : base(sender)
{
messageTest = editTest;
}
}
DetailViewModel
public TestViewModel EditTest
{
get { return _editTest; }
set
{
_editTest = value;
RaisePropertyChanged(() => EditTest);
}
}
public DetailViewModel(IMvxMessenger messenger)
{
_messenger = messenger;
}
public void Save()
{
UpdateValues();
}
public void UpdateValues()
{
var message = new TestMessage(this, _editTest);
_messenger.Publish(message, typeof(TestMessage));
}
public void Init(Parameter param)
{
_editTest = new TestViewModel();
_editTest.Age = param.Age;
_editTest.Name = param.Name;
_editTest.Gender = param.Gender;
public class Parameter
{
public double Age { get; set; }
public int Gender { get; set; }
public string Name { get; set; }
}
DetailView xml
<EditText
style="@style/InputNumbersEditText"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="44dp"
android:gravity="center_vertical|right"
android:hint="00.000"
local:MvxBind="Text EditTest.Age, Converter=Nullable;" />
TestViewModel
public class TestViewModel : BaseViewModel
{
public string? Name { get; set; }
public double? Age { get; set; }
public int? Gender { get; set; }
}
NullableValueConverter
public class NullableValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (string.IsNullOrEmpty(value?.ToString()))
{
return parameter;
}
return value;
}
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || string.IsNullOrEmpty(value.ToString()))
{
return null;
}
return value;
}
}
Upvotes: 0
Views: 56
Reputation: 14760
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}
This can't work, because your are just changing the reference of _selectedItem
to point to another object. But this object is not included in the list that is used to show in the recycler view. You are not updating a object, just a reference! You should definitely have a look at the basics of C# to understand this kind of data structure. E.g. Reference vs. Value Type
Your code is a bit faulty.
SelectedItem
has the type MainViewModel
Your click command gets a item of type TestViewModel
public virtual ICommand ItemSelected
{
get
{
return new MvxCommand<TestViewModel>(item =>
{
SelectedItem = item;
});
}
}
Normally this should work:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age= obj.messageTest.Age;
_selectedItem.Name= obj.messageTest.Name;
_selectedItem.Gender= obj.messageTest.Gender;
}
but with a TestViewModel
like
public class TestViewModel : BaseViewModel
{
private string? name;
public string? Name { get{ return name; } set { SetProperty(ref name, value); } }
// same for Age and Gender
}
SetProperty
sets the value and calls the OnPropertyChanged event.
Upvotes: 3
Reputation: 5192
Updated Answer
Assigning the _selectedItem
a new TestViewModel
breaks the reference link it has to the TestViewModel
held in the TestsViews
data source list. While assigning the individual properties maintains the reference to the orginal TestViewModel
in the TestsViews
list.
Orginal Answer
As you are updating the backing field, _selectedItem
, so when you receive the message event the RaisePropertyChanged
event defined in the set of your SelectedItem
property will never run. You will have to manually trigger the RaisePropertyChanged
in order to trigger the binding update.
Try changing your current method:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
}
To raise the property changed event:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem = obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}
Upvotes: 0