uwp-'该应用程序调用了一个已编组用于另一个线程的接口

时间:2018-07-18 21:57:11

标签: c# multithreading mvvm binding uwp

我正在尝试使用MVVM创建UWP聊天。我不断收到此错误:

  

该应用程序调用了一个已编组为不同线程的接口

在这里我的视图模型中:

public void Notify(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

每当将值设置为绑定到xaml中TextBlock.Text属性的字符串属性时,就会发生此函数;

我尝试在视图模型中插入TextBlock(即vm已绑定到其text属性),并删除了xaml中的所有绑定并使用此功能:

private async Task LoadMessage(string sender, string message)
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            ChatBox += $"{sender}: {message} \n";
        });
    }

仍然相同,只是现在上面的函数中引发了异常。

我在寻找答案时发现了花药调度员,但uwp似乎无法识别它,并用红色下划线标记了它:

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            //my code           
        });

我尝试过:

await CoreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
        {
            ChatBox += $"{sender}: {message} \n";
        });

但是后来我得到了

  

非静态字段方法需要对象引用

所以我创建了一个包含此函数的静态类:

public static void UpdateTextBlock(TextBlock textBlock, string sender, string message)
    {

        textBlock.Text = $"{sender}: {message}";
    }

并将其插入此调度程序。还是不行。仍然:...需要对象引用。

我真的希望它成为MVVM,但是任何可行的解决方案都是一个福音。

编辑

今天,我尝试回到绑定和mvvm模式。我将LoadMessage函数包装在这样的任务中:

private async Task<bool> LoadMessage(string sender, string message)
    {
        bool flag = false;
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            TextBindingProperty += $"{sender}: {message} \n";
            flag = true;
        });

        return flag;
    }

_hubProxy.On<string, string>("SendMessage", async (sender, message) =>
        {
            var result = await Task.Run(() => LoadMessage(sender, message));
        });

仅在类中存在相同的例外:MyView.g.cs

在这种方法中:

public static void Set_Windows_UI_Xaml_Controls_TextBlock_Text(global::Windows.UI.Xaml.Controls.TextBlock obj, global::System.String value, string targetNullValue)
        {
            if (value == null && targetNullValue != null)
            {
                value = targetNullValue;
            }
            obj.Text = value ?? global::System.String.Empty; //in this line!!!
        }
    };

我的视图模型实现INotifyPropertyChanged

 public class UserViewModel : INotifyPropertyChanged
{
private string chatBox;

    public string ChatBox
    {
        get { return chatBox; }
        set { chatBox = value; Notify(nameof(ChatBox)); }
    }

 public event PropertyChangedEventHandler PropertyChanged;

    public void Notify(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

与该属性绑定的xaml元素如下所示:

 <TextBlock Name="chatTbl"  Text="{x:Bind userViewModel.ChatBox, Mode=TwoWay}" />

2 个答案:

答案 0 :(得分:1)

解决方案:

所以要努力使聊天正常进行,这就是问题所在:

await CoreApplication.MainView

由于聊天与首页的视图不同,因此找不到绑定或xaml元素。

我的朋友意识到要在其他视图中进行更改,您需要获取其对象,因此,我们将此属性添加到了视图模型中:

  public CoreApplicationView CurrentView { get; set; }

启动聊天室视图时,我们设置属性:

public UserViewModel userViewModel;
    public ChatRoom(UserViewModel userViewModel)
    {
        this.InitializeComponent();
        this.userViewModel = userViewModel;
        userViewModel.ChatTbl = chatTbl;


        userViewModel.CurrentView = CoreApplication.GetCurrentView();//this line

    }

现在,当我们需要在视图中进行更改时,我们将使用:

 _hubProxy.On<string, string>("SendMessage", async (sender, message) =>
        {

            await CurrentView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                ChatTbl.Text += $"{sender}: {message} \n";
            });
        });

所以改为await CoreApplication.MainView

使用await CurrentView.CoreWindow

希望这会对我认识的人有所帮助

答案 1 :(得分:0)

您的LoadMessage是一种异步方法,您无需将其放在Task.Run中。您可以像下面这样直接调用它:

_hubProxy.On<string, string>("SendMessage", async (sender, message) =>
    {
        var result = await LoadMessage(sender, message);
    });

如果必须将其放在Task.Run中,可以这样称呼它:

_hubProxy.On<string, string>("SendMessage", async (sender, message) =>
    {
        var result = await Task.Run(async() => await LoadMessage(sender, message));
    });