Обновить привязку MVVM к событию, запущенному асинхронной задачей - PullRequest
0 голосов
/ 11 января 2019

У меня есть задача, которая запускает операцию непрерывного чтения TCP, когда эта операция чтения читает закодированное в JSON сообщение с удаленного сервера, она отправляет событие в класс Command.cs, где обрабатывает необработанный JSON и преобразует его в класс Response, выполните необходимые проверки и затем инициирует событие «Завершено», когда в конечном итоге клиент подписывается на то, где он может получить класс Response, который можно добавить в наблюдаемую коллекцию.

Я пытался реализовать RaisePropertyChanged, который вызывает функцию Invoke в Dispatcher, которая должна корректно обновлять ObservableCollection.

TCPRequest.cs

private static CancellationTokenSource cancellation;

private static event OnDataReceived datareceivedevent;

public static event OnDataReceived DataReceivedEvent
{
        add
        {
            if(datareceivedevent == null)
            {
                datareceivedevent += value;
            }
        }
        remove
        {
            datareceivedevent -= value;
        }
    }

private static async void ReadOperation(object t)
    {
        var token = (CancellationToken)t;
        var stream = tcpClient.GetStream();
        var byteBuffer = new byte[tcpClient.ReceiveBufferSize];

        while (!token.IsCancellationRequested)
        {
            int lRead = 0;
            if (stream.DataAvailable)
            {

                lRead = await stream.ReadAsync(byteBuffer, 0, byteBuffer.Length);
            }
            if (lRead > 0)
            {
                var response = ASCIIEncoding.ASCII.GetString(byteBuffer, 0, lRead);


                datareceivedevent(response);
            }
        }
    }
public static void StartReading()
    {
        Task.Factory.StartNew(ReadOperation, cancellation.Token, cancellation.Token);
    }

Приведенный выше код является задачей, которая выполняется до тех пор, пока не будет запрошена отмена. Когда данные доступны, они преобразуются в строку и запускают событие (показано выше).

Command.cs

public event OnDataReceivedDeserialized OnDataReceivedDeserialized;

public bool Execute()
    {
        this.JSONFormat = ToJson();

        TCPRequest.DataReceivedEvent += TCPRequest_DataReceivedEvent;

        if (!JSONFormat.Equals(string.Empty))
        {
            return TCPRequest.SendToServer(this);
        }
        else
        {
            return false;
        }
    }

Функция execute находится в классе Command, который обрабатывает все необходимое для отправки JSON на сервер. Этот класс Command подписывается на событие TCPRequest datareceivedevent.

  if (TCPRequest.IsConnected)
            {
                Command cmd = new Command();
                cmd.RequestCommand = new Request(RequestType.info);
                cmd.OnDataReceivedDeserialized += Cmd_OnDataReceivedDeserialized;
                cmd.Execute();  
            }

    public void Cmd_OnDataReceivedDeserialized(RequestResponse response)
        {
            LoPyList.Add(new LoPy() { name = "Test", id = "00" });
        }

А затем над ним будет создана команда, которая подписывается на командное событие, куда пойдет значение ответа сервера.

GraphViewModel.cs

private ObservableCollection<LoPy> lopyList;
    public ObservableCollection<LoPy> LoPyList
    {
        get { return lopyList; }
        set {
            lopyList = value;
            RaisePropertyChangedEvent("LoPyList"); }
    }

И, наконец, над списком LoPyList, который привязан к комбинированному списку интерфейса.

GraphView.xaml

<ComboBox Grid.Row="1" ItemsSource="{Binding Path=LoPyList}" 
DisplayMemberPath="name"/>

Мне нужно то, что функция внутри ViewModel обновляет LoPyList и я могу просматривать его в пользовательском интерфейсе.

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Оказалось, что я дважды инициализирую модель представления и использую вторую модель представления, которая не связана с представлением. Потом я использовал диспетчер, и он работает как брелок.

Спасибо за помощь!

0 голосов
/ 11 января 2019

Когда ваше событие срабатывает, вы вызываете метод «Добавить» в ObservableCollection:

LoPyList.Add(new LoPy() { name = "Test", id = "00" });

Проблема в том, что ваш RaisePropertyChangedEvent возникает только при установке свойства LoPyList. Когда вы вызываете Add (), сеттер не запускается, поэтому RaisePropertyChangedEvent никогда не вызывается и ваша привязка никогда не обновляется.

Что вы можете сделать, это добавить: RaisePropertyChangedEvent("LoPyList"); после вызова Add ():

public void Cmd_OnDataReceivedDeserialized(RequestResponse response)
{
    LoPyList.Add(new LoPy() { name = "Test", id = "00" });
    RaisePropertyChangedEvent(nameof(LoPyList));
}

В качестве альтернативы ObservableCollection предоставляет событие CollectionChanged , которое

Происходит при добавлении, удалении, изменении, перемещении или обновлении всего списка.

Вы можете подключиться к этому событию и затем позвонить RaisePropertyChangedEvent("LoPyList");

...