Модель не обновляется - PullRequest
0 голосов
/ 13 июня 2018

Я прошу прощения за этот длинный вопрос, но я надеюсь, что вы можете остаться со мной.Я пытался сделать все возможное, чтобы включить все соответствующие фрагменты кода, чтобы точно объяснить, чего я хочу достичь.

Я пытаюсь преобразовать свое мобильное приложение в шаблон проектирования MVVM, и я испытываю немногосложность с обновлением моего представления с учетом изменений, произошедших в моей модели.

Я разделил свое приложение на классическую структуру модель, вид, вид модель.

В настоящее время я пытаюсь распространить данные из моей модели SoundScapeData.cs в мое представление HomePage.xaml.

Мой HomePage.xaml файл с выделенным кодом выглядит следующим образом:

namespace AX2018
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class HomePage : ContentPage
    {
        public HomePage()
        {
            InitializeComponent();
            BindingContext = new HomePageViewModel();
        }

        private void OnConnectButtonClicked(object sender, EventArgs e)
        {
            Bluetooth bluetooth = new Bluetooth();
            bluetooth.Connect();
        }
    }
}

Как видите, я связываю свои данные с помощью ключевого слова BindingContext и привязываю их к новому экземплярукласс HomePageViewModel.

Я подключаюсь к устройству Bluetooth, поэтому выполняется вызов bluetooth.Connect(), который вызывается при нажатии Button в представлении HomePage.xaml.Это устройство Bluetooth затем обновляет приложение с определенными значениями.

Хочу подчеркнуть, что соединение Bluetooth работает хорошо, и было проверено, что он работает с View до для преобразования в шаблон проектирования MVVM.

My ViewModel, HomePageViewModel.cs, выглядит следующим образом:

namespace AX2018
{
    public class HomePageViewModel
    {
        private SoundScapeData _soundScapeData;

        public SoundScapeData SoundScapedata { get { return _soundScapeData; } }

        public HomePageViewModel()
        {
            _soundScapeData = new SoundScapeData();
        }
    }
}

Кстати, я немного запутался, как проектировать модель представления, поскольку модель SoundScapeData.cs в настоящее время так проста, как есть.Является ли этот посредник View Model даже необходимым?

Это моя SoundScapeData.cs модель:

namespace AX2018
{
    public class SoundScapeData : INotifyPropertyChanged
    {
        private double _spl;

        public double SPL
        {
            get { return _spl; }
            set
            {
                _spl = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Как вы можете видеть из модели, она реализует интерфейс INotifyPropertyChanged и имеетсоответствующая функция для обработки события в методе OnPropertyChanged().

My View, HomePage.xaml, довольно длинная - она ​​состоит из сетки 9 x 3 с метками, размещенными в определенных положениях.Эти метки должны отражать значения в SoundScapeData.cs модели (и других моделях, но это в будущем).Вот соответствующие фрагменты:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:AX2018"
         x:Class="AX2018.HomePage">

<ContentPage.BindingContext>
    <local:HomePageViewModel/>
</ContentPage.BindingContext>

...

<Label Text="{Binding SoundScapedata.SPL}" 
FontSize="68" Style="{StaticResource ColoredLabel}" 
Grid.Row="4" 
Grid.Column="1" 
Margin="-20"></Label>

Как вы можете видеть, я связал данные в представлении HomePage.xaml с моделью представления HomePageViewModel.cs, которая содержит экземпляр модели SoundScapeData.cs,который в свою очередь реализует интерфейс INotifyPropertyChanged.

Насколько я понимаю, это правильный подход с точки зрения привязки данных при использовании шаблона проектирования MVVM.Тем не менее, изменения в SPL не отражены в моем представлении HomePage.xaml.

Я обновляю значение SPL в отдельном классе Bluetooth.cs, который наследуется от модели SoundScapeData.cs.Вот фрагмент из Connect() метода из Bluetooth класса:

namespace AX2018
{
    public async void Connect()
    {
        public class Bluetooth : SoundScapeData
        ...
        var dbValue = (double)BitConverter.ToUInt16(temp1, 0) / 256 * 48;
        SPL = dbValue;
        ...
    }
}

Снова, я прошу прощения за этот довольно длинный вопрос, но я надеюсь, что кто-то там может указать мне, что я делаюнеправильно.Я хочу повторить, что значение SPL обновилось в View до до преобразования в MVVM, поэтому я определенно делаю что-то не так с моей привязкой данных.

Заранее спасибо,

kdhansen

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Ваша проблема в том, что вы меняете экземпляр модели и теряете привязку вида.Ответ Хуана Карлоса правильный, вы не применяете чистый MVVM, представление не должно знать модель, модель представления отвечает за адаптацию модели к представлению.OnConnectButtonClicked, который вы имеете в коде позади представления, также не применяет шаблон MVVM, вы должны использовать Commands.Ссылка http://www.learnmvvm.com/ является хорошей отправной точкой.

Если вы загрузите пример проекта своего кода в какой-либо репозиторий, я изменю его, применив принципы MVVM и SOLID.

0 голосов
/ 13 июня 2018

Я отвечу здесь, потому что комментарии слишком короткие, чтобы их объяснить.Если я неправильно ввожу некоторые имена, извините меня: P Давайте подведем итог вашего сценария:

  • HomePage - это ваше представление
  • HomePageViewModel - это ваша виртуальная машина
  • SoundScapeData - ваша модель

Теперь:

Домашняя страница (просмотр)

Я действительно не знаю, нужно ли в Xamarin oyu дублировать это, помните, что вы установили его в своем кодепозади.

<ContentPage.BindingContext>
<local:HomePageViewModel/>
</ContentPage.BindingContext>

Вы также должны изменить это:

<Label Text="{Binding Spl}" <!--You dont need SoundScapeData anymore this is the public VM property -->
FontSize="68" Style="{StaticResource ColoredLabel}" 
Grid.Row="4" 
Grid.Column="1" 
Margin="-20"></Label>

HomePageViewModel

В нем должно быть столько свойств, сколько вам нужно.Допустим, ваша модель имеет только одно свойство SPL .Это ваша модель, теперь вы должны поместить ее в View через виртуальную машину.Таким образом, у вашей виртуальной машины должно быть свойство (публичное / частное), чтобы адаптировать его к представлению и вашей модели.

private string spl;
public string Spl
       {
         get {return this.spl;}
         set
            {
            if (this.spl != value)
            {
            this.spl = value;
            OnPropertyChanged("SPL);
            }

Когда вы нажимаете кнопку и подключаетесь к Bluetooth или к чему-либо еще (; P)поскольку это меняет модель, вы должны изменить свои свойства виртуальной машины.Помните, ваша модель должна быть таким же, как у вашей виртуальной машины.

Итак ... вам следует присоединить измененное свойство Model, чтобы изменить свойства виртуальной машины, и лучший способ сделать это - создать класс (давайте попробуем применить SOLID как можно больше)

public class YourNewDataSource
{
    #region Attributes

    private readonly HomePageViewModel homePageViewModel;

    #endregion

    #region Public Methods


    public YourNewDataSource(HomePageViewModel homePageViewModel)
    {
      this.homePageViewModel = homePageViewModel;
    }

    public void Initialize()
    {
        this.homePageViewModel.SoundScapeData.PropertyChanged += this.OnHomePageModelPropertyChanged;
    }

    #endregion

    #region Event Handlers

    private void OnHomePageModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "SPL":
                this.homePageViewModel.Spl = this.homePageViewModel.SoundScapeData.Spl;
                break;
        }
    }

    #endregion
}

Теперь, когда вы запускаете приложение или хотите показать свое представление, вам нужно создать новый YourNewDataSource с вашей виртуальной машиной:

public HomePage()
    {
        InitializeComponent();
        HomePageViewModel homePageViewModel = new HomePageViewModel();
        YourNewDataSource yourNewDataSource = new YourNewDataSource(homePageViewModel)
        BindingContext = homePageViewModel;
    }

Посмотрите, попробуйте и спросите, не хотите ли выПолучите немного *** Я только что написал здесь: D


Я только что посмотрел на ваш bluetooth.Connect.

Я не знаю, является ли это обязательнымчтобы класс Bluetooth унаследовал от SoundScapeData, но сейчас он не будет работать, потому что вы теряете модель виртуальной машины при подключении.Если вам не нужно наследовать от SoundScapeData, просто добавьте параметр в метод connect и передайте ему Vm.SoundScapeData.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...