从异步任务触发的事件中更新MVVM绑定

时间:2019-01-11 16:47:02

标签: c# events mvvm task

我有一个运行连续TCP读取操作的任务,当该读取操作从远程服务器读取JSON编码的消息时,它将向Command.cs类触发一个事件,在该类中它将处理原始JSON并将其转换为响应类,进行必要的检查,然后触发“完成”事件,最终客户端在该事件中订阅,他们可以接收可以添加到Observable集合的响应类。

我试图实现一个RaisePropertyChanged,该调用在Dispatcher上调用Invoke函数,该函数应正确更新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,并且可以在UI中查看它。

2 个答案:

答案 0 :(得分:0)

事件触发时,您正在执行的操作是在ObservableCollection上调用“添加”方法:

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

这里的问题是您的RaisePropertyChangedEvent仅在设置LoPyList属性时出现。当您调用Add()时,setter不会运行,因此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");

答案 1 :(得分:0)

原来,我两次初始化了视图模型,并使用了未连接到视图的第二个视图模型。之后,我使用了调度程序,它的工作原理就像一种魅力。

感谢您的帮助!