【问题标题】:uwp - 'The application called an interface that was marshalled for a different threaduwp - '应用程序调用了一个为不同线程编组的接口
【发布时间】:2018-12-26 22:28:58
【问题描述】:

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

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

在我的视图模型中:

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

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

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

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

还是一样,只是现在在上面的函数中抛出了异常。

我在搜索答案时发现了 anther dispatcher,但似乎 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}" />

【问题讨论】:

  • 而不是显示这些,只是向我们展示您的 ViewModel(全部,如果不是太大)现在的样子以及当前的错误是什么。另外,也显示 xaml 部分。
  • 试一试:在加载消息中使用 CoreApplication.MainView..... 并将 PropertyChanged 包装在另一个任务中(不是 UI 任务)
  • @TheTanic 在 LoadMessage 中不是我做的吗? LoadMessage 返回任务,在其中我使用了 CoreApplication.MainView。将 propertyChanged 包装在另一个任务中是什么意思?你能显示代码吗?谢谢
  • @Muzib 我根据您的要求编辑了帖子

标签: c# multithreading mvvm binding uwp


【解决方案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

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

【讨论】:

    【解决方案2】:

    你的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));
        });
    

    【讨论】:

      猜你喜欢
      • 2023-03-20
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      相关资源
      最近更新 更多