c# - 当我从 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
}
}
解决方案
你需要使用
Device.BeginInvokeOnMainThread( () => {
// whatever UI operation you need goes here
});
强制您的 UI 代码从后台线程在主 (UI) 线程上执行
推荐阅读
- uml - 如何通过关联类导航以使用 OCL 创建约束?
- java - RESTAPI 读取图像并转换为 BLOB
- r - 将列表中的主要标题添加到 for 循环中的图形
- jquery - ODOO - 菜单下拉菜单_点击外部折叠
- arrays - Google Sheets Query - 动态构建引用的数组源
- sql - 插入日期给出错误 ORA-01861:文字与格式字符串不匹配
- php - Wordpress 类别 URL 名称而不是 slug
- ios - iOS 设备不使用 PWA-Icon
- powershell - 码头工人和提升的私人
- authentication - Openshift 配置“请求标头”身份验证