在MainViewMode中从Main发送数据到Detail和更新对象

时间:2016-04-23 00:29:37

标签: data-binding xamarin xamarin.android mvvmcross

我有以下recyclerview,其中包含TestViewModel个对象的列表。在此对象中,我有agegendername属性。我试图在用户点击列表项时实现,它需要用户详细查看用户能够更新的位置并单击保存按钮,然后更新所选项属性。

问题:

MainViewModel中的以下代码,当我收到详细信息中的值并更新每个属性时,我收到来自DetailViewModel的消息,

private void OnMessageReceived(TestMessage obj)
{
    _selectedItem.Age = obj.messageTest.Age;
    _selectedItem.Name = obj.messageTest.Name;
    _selectedItem.Gender = obj.messageTest.Gender;
}

但是下面这段代码在我试图直接更新对象的地方不起作用。

private void OnMessageReceived(TestMessage obj)
{
    _selectedItem= obj.messageTest;
    RaisePropertyChanged(() => SelectedItem);
}

代码实施如下:

<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;
    }
}

2 个答案:

答案 0 :(得分:3)

private void OnMessageReceived(TestMessage obj)
{
    _selectedItem= obj.messageTest;
    RaisePropertyChanged(() => SelectedItem);
}

这不起作用,因为您只是将_selectedItem的引用更改为指向另一个对象。但是此对象未包含在用于在回收器视图中显示的列表中。您更新对象,只是一个参考!您一定要了解C#的基础知识,以了解这种数据结构。例如。 Reference vs. Value Type

您的代码有点错误。

  • SelectedItem的类型为MainViewModel
  • 您的点击命令会获得TestViewModel

    类型的项目
    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;
}

但是有TestViewModel之类的

public class TestViewModel : BaseViewModel
{
    private string? name;
    public string? Name { get{ return name; } set { SetProperty(ref name, value); } }
    // same for Age and Gender
}

SetProperty设置值并调用OnPropertyChanged事件。

答案 1 :(得分:0)

更新了答案

_selectedItem分配新的TestViewModel会将其对TestViewModel数据源列表中保存的TestsViews的引用链接断开。分配各个属性时,会保留TestViewModel列表中原始TestsViews的引用。

原始回答

在更新支持字段_selectedItem时,所以当您收到消息事件时,RaisePropertyChanged属性集中定义的SelectedItem事件将永远不会运行。您必须手动触发RaisePropertyChanged才能触发绑定更新。

尝试更改您当前的方法:

private void OnMessageReceived(TestMessage obj)
{
    _selectedItem= obj.messageTest;
}

提升属性更改事件:

private void OnMessageReceived(TestMessage obj)
{
    _selectedItem = obj.messageTest;
    RaisePropertyChanged(() => SelectedItem);
}