首页 > 解决方案 > 当我从 tcp 客户端接收数据时,我无法从 ViewModels 的 xaml 页面进行更改

问题描述

我正在学习 xamarin.forms 和 wpf。我被困在这里:

我的应用程序中有 tcp 服务器,当我的 tcp 服务器从客户端接收数据时,我的事件(在 ViewModelBase 中)被触发,然后它必须在当前 xaml 页面上显示数据,但它没有显示。任何人都知道我应该如何将此事件与当前的 xaml 页面绑定。

我想要的是当 Tcp 客户端向我发送数据(它只是字符串)时,我想用 DisplayAlert 在屏幕上显示这些数据。

如果我使用按钮,它可以工作,但不是我想要的。

ViewModelBase 类

public class ViewModelBase : BindableBase, INavigationAware, IDestructible
{
    protected INavigationService NavigationService { get; private set; }
    protected IPageDialogService DialogService { get; private set; }

    public static ProxyServer Client { get; set; }
    public ObservableCollection<Item> ListItems { get; set; }

    private DelegateCommand _eventCommand;
    public DelegateCommand EventCommand
    {
        get { return _eventCommand; }
        set { SetProperty(ref _eventCommand, value); }
    }
    public DelegateCommand DisconnectCommand { get; set; }

    private object _lockObj = new object();

    public ViewModelBase(INavigationService navigationService,IPageDialogService dialogService)
    {
        Client = ProxyServer.GetInstance();

        EventCommand = new DelegateCommand(Client_ListenServer, () => { return true; });
        DisconnectCommand = new DelegateCommand(Disconnect, () => { return true; });

        NavigationService = navigationService;
        DialogService = dialogService;
        ListItems = new ObservableCollection<Item>()
        {
            new Item()
            {
                Id = "0",
                Name = "Android",
                Description = "Android Mobil"
            },
            new Item()
            {
                Id = "1",
                Name = "IOS",
                Description = "IOS Mobil"
            },
              new Item()
            {
                Id = "2",
                Name = "UWP",
                Description = "UWP Mobil + From"
            }
        }; // sample
    }

    private void Client_ListenServer()
    {
        Debug.WriteLine("I'm triggered");
        DialogService.DisplayAlertAsync("test title", "message", "OK !", "cancel");
    }

    private void Disconnect()
    {
        Client.Disconnect();
        RemoveEventHandler();
        DialogService.DisplayAlertAsync("Status", "Disconnected..", "OK");
    }

    #region NavigationMethods
    public virtual void OnNavigatedFrom(NavigationParameters parameters)
    {
        RemoveEventHandler();
    }
    public virtual void OnNavigatedTo(NavigationParameters parameters)
    {
        if (Client.ConnectedStatus())
            AddEventHandler();
    }
    public virtual void OnNavigatingTo(NavigationParameters parameters) 
    {
        RemoveEventHandler();
    }

    public virtual void Destroy()
    {

    }
    #endregion

    private void Client_ListenServer(object sender, EventArgs e)
    {
        Client_ListenServer(); // this method must show dialogAlert on current page
    }

    public void RemoveEventHandler()
    {
        Client.ListenServer -= Client_ListenServer;
    }
    public void AddEventHandler()
    {
        Client.ListenServer += Client_ListenServer;
    }
}

Client_ListenServer 方法触发但 DisplayAlert 不起作用。

当前的 xaml 页面。

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="DataViewer.Views.Login"
             Title="{Binding Title}">
    <ContentPage.Content>
        <StackLayout VerticalOptions="CenterAndExpand" Spacing="20" Padding="20"> 
            <Entry  Text="{Binding Username}" Placeholder="Username"/>
            <Entry Text="{Binding Password}" Placeholder="Password" IsPassword="true"/>
            <Button Text="Login" VerticalOptions="CenterAndExpand" Command="{Binding AuthorizeCommand}"/>

        </StackLayout>
    </ContentPage.Content>
    <ContentPage.ToolbarItems>
        <ToolbarItem Name="MenuItem1" Order="Secondary" Text="Connect" Command="{Binding ConnectCommand}"/>
        <ToolbarItem Name="MenuItem2" Order="Secondary" Text="Disconnect" Command="{Binding DisconnectCommand}" />
        <ToolbarItem Name="MenuItem2" Order="Secondary" Text="Get Data" Command="{Binding EventCommand}" />
    </ContentPage.ToolbarItems>
</ContentPage>

我的 app.cs

public partial class App : PrismApplication
    {
        public App() : this(null) { }

        public App(IPlatformInitializer initializer) : base(initializer) { }

        protected override async void OnInitialized()
        {
            InitializeComponent();
            await NavigationService.NavigateAsync("NavigationPage/ConnectionPage");
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<NavigationPage>();
            containerRegistry.RegisterForNavigation<Login, LoginViewModel>();
            containerRegistry.RegisterForNavigation<Views.ListView, ListViewModel>();
            containerRegistry.RegisterForNavigation<Item, ItemViewModel>();
            containerRegistry.RegisterForNavigation<ConnectionPage>();
        }
    }

Android mainActivity 类

  [Activity(Label = "DataViewer", Icon = "@mipmap/ic_launcher", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);
            UserDialogs.Init(this);
            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App(new AndroidInitializer()));
        }

    }

    public class AndroidInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IContainerRegistry container)
        {
            // Register any platform specific implementations
        }
    }

标签: c#wpfdata-bindingxamarin.formsprism

解决方案


你需要使用

Device.BeginInvokeOnMainThread( () => {
  // whatever UI operation you need goes here
});

强制您的 UI 代码从后台线程在主 (UI) 线程上执行


推荐阅读