C# Xamarin表单MVVM更新不适用于UWP
我有以下代码:C# Xamarin表单MVVM更新不适用于UWP,c#,mvvm,xamarin.forms,xamarin.uwp,C#,Mvvm,Xamarin.forms,Xamarin.uwp,我有以下代码: Device.StartTimer(TimeSpan.FromSeconds(1), () => { foreach (var detail in Customer.Details.Where(p => new string[] { "Queue", "Wating"}.Contains(p.Status))) { detail.HasTimer = true; detail.Time =
Device.StartTimer(TimeSpan.FromSeconds(1),
() =>
{
foreach (var detail in Customer.Details.Where(p => new string[] { "Queue", "Wating"}.Contains(p.Status)))
{
detail.HasTimer = true;
detail.Time = detail.Time.Add(TimeSpan.FromSeconds(1));
}
return true;
});
这段代码在我将其部署到android时运行良好,但在UWP中,信息只是在UI中被删除
我还尝试使用methdo Device.BeginInvokeMainThread,但得到了相同的结果
每个属性都实现INotifyPropertyChanged,详细信息是一个可观察集合,它也实现INotifyPropertyChanged
我正在使用Visual Studio 2017社区
XAML如下所示:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Bulingo.CCC.Mobile.Views.TicketDigital">
<ContentView.Content>
<StackLayout >
<StackLayout.VerticalOptions>
<LayoutOptions Alignment="Center">
</LayoutOptions>
</StackLayout.VerticalOptions>
<Button IsVisible="{Binding MostrarBoton}"
Text="Leer Código"
VerticalOptions="Center"
HorizontalOptions="Center"
TextColor="White"
BackgroundColor="#77D065"
Command="{Binding ReadQRCodeCommand}"/>
<Label FontAttributes="Bold"
TextColor="Red"
Text="El Código QR leído no es válido."
IsVisible="{Binding MostrarErrorQrCode}"/>
<Label FontAttributes="Bold"
TextColor="Red"
Text="Por favor verifique su conexión de red."
IsVisible ="{Binding MostrarErrorConexion}"
/>
<StackLayout VerticalOptions="FillAndExpand" IsVisible="{Binding MostrarServicios}">
<Image Aspect="Fill">
<Image.Source>
<UriImageSource Uri="{Binding LogoUrl}" />
</Image.Source>
</Image>
<StackLayout Orientation="Horizontal">
<Label FontSize="Large">Número</Label>
<Label Text="{Binding Cliente.Numero}" FontSize="Large"/>
</StackLayout>
<ListView ItemsSource="{Binding Cliente.Detalles}" SeparatorColor="Yellow" RowHeight="160">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell BindingContext="{Binding}" >
<Frame OutlineColor="Accent" >
<ContentView Padding="1" Margin="2" >
<StackLayout >
<Label Text="{Binding Servicio}" FontSize="Medium"/>
<StackLayout Orientation="Horizontal" >
<Label Text="Sala de Espera"/>
<Label Text="{Binding SalaEspera}" HorizontalOptions="End"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Tiempo Transcurrido"/>
<Label Text="{Binding TiempoTranscurridoText}" TextColor="{Binding TiempoTranscurridoColor}"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Personas delante"/>
<Label Text="{Binding TotalEnCola}"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Estado"/>
<Label Text="{Binding Estado}" FontAttributes="Bold"/>
</StackLayout>
</StackLayout>
</ContentView>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
<StackLayout VerticalOptions="FillAndExpand" IsVisible="{Binding MostrarFormularioEncuesta}">
<Button HorizontalOptions="End"
Command="{Binding CancelSurveyCommand}"
Text="No quiero llenar la encuesta..."/>
<Button Command="{Binding SaveSurveyCommand}" Text="Enviar"
TextColor="White"
BackgroundColor="#77D065"
HorizontalOptions="End"/>
<TableView Intent="Form">
<TableRoot Title="Llenar Encuesta" BindingContext="{Binding Encuesta}">
<TableSection Title="Método preferido">
<ViewCell>
<Picker SelectedIndex="{Binding BetterOrWorseInt}">
<Picker.Items>
<x:String>No estoy Seguro</x:String>
<x:String>Sin Sistema</x:String>
<x:String>Con Sistema</x:String>
</Picker.Items>
</Picker>
</ViewCell>
</TableSection>
<TableSection Title="Con el nuevo sistema, ¿la atención es más rápida o más lenta?">
<ViewCell>
<Picker SelectedIndex="{Binding SpeedInt}">
<Picker.Items>
<x:String>No estoy Seguro</x:String>
<x:String>Más lenta</x:String>
<x:String>Más rápida</x:String>
</Picker.Items>
</Picker>
</ViewCell>
</TableSection>
<TableSection Title="¿Desearía que instalemos el sistema en otras áreas o sucursales?">
<ViewCell>
<Picker SelectedIndex="{Binding ExpandInt}">
<Picker.Items>
<x:String>No estoy Seguro</x:String>
<x:String>No, no me gustaría</x:String>
<x:String>Sí, me gustaría</x:String>
</Picker.Items>
</Picker>
</ViewCell>
</TableSection>
<TableSection Title="¿Qué piensa de la calidad del nuevo sistema?">
<ViewCell>
<StackLayout HorizontalOptions="Fill">
<AbsoluteLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Slider Minimum="0" Maximum="5" WidthRequest="200" Value="{Binding QualityDouble}" Scale="1"
AbsoluteLayout.LayoutBounds="0, 0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"
/>
<Label Text="{Binding QualityText}" HorizontalOptions="Center" HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0, 1"
AbsoluteLayout.LayoutFlags="PositionProportional"
/>
</AbsoluteLayout>
</StackLayout>
</ViewCell>
</TableSection>
<TableSection Title="¿Qué tan fácil es adaptarse al nuevo sistema?">
<ViewCell>
<StackLayout HorizontalOptions="Fill">
<AbsoluteLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Slider Minimum="0" Maximum="5" WidthRequest="200" Value="{Binding EasinessDouble}" Scale="1"
AbsoluteLayout.LayoutBounds="0, 0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"
/>
<Label Text="{Binding EasinessText}" HorizontalOptions="Center" HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0, 1"
AbsoluteLayout.LayoutFlags="PositionProportional"
/>
</AbsoluteLayout>
</StackLayout>
</ViewCell>
</TableSection>
<TableSection Title="Sugerencias para el Sistema">
<ViewCell >
<Editor Text="{Binding NotesForBulingo}" HeightRequest="100" />
</ViewCell>
</TableSection>
<TableSection Title="Sugerencias general">
<ViewCell>
<Editor Text="{Binding NotesForClient}" HeightRequest="100"/>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
</StackLayout>
<StackLayout VerticalOptions="FillAndExpand" IsVisible="{Binding MostrarAgradecimiento}">
<Label FontSize="Large"
FontAttributes="Bold"
Text="¡Gracias por usar nuestros servicios y gracias por llenar nuestra encuesta!"></Label>
<Image Aspect="AspectFill">
<Image.Source>
<UriImageSource Uri="{Binding LogoUrl}" />
</Image.Source>
</Image>
<StackLayout Orientation="Horizontal">
<Label FontSize="Large">Número</Label>
<Label Text="{Binding Cliente.Numero}" FontSize="Large"/>
</StackLayout>
<ListView ItemsSource="{Binding Cliente.Detalles}" SeparatorColor="Yellow" RowHeight="160">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell BindingContext="{Binding}" >
<Frame OutlineColor="Accent" >
<ContentView Padding="1" Margin="2" >
<StackLayout >
<Label Text="{Binding Servicio}" FontSize="Medium"/>
<StackLayout Orientation="Horizontal" >
<Label Text="Sala de Espera"/>
<Label Text="{Binding SalaEspera}" HorizontalOptions="End"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Tiempo Transcurrido"/>
<Label Text="{Binding TiempoTranscurridoText}" TextColor="{Binding TiempoTranscurridoColor}"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Personas delante"/>
<Label Text="{Binding TotalEnCola}"/>
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="Estado"/>
<Label Text="{Binding EstadoAtencion}" FontAttributes="Bold"/>
</StackLayout>
</StackLayout>
</ContentView>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
<ActivityIndicator Color="Red" IsRunning="{Binding IsBusy}" />
</StackLayout>
</ContentView.Content>
</ContentView>
努梅罗
没有estoy Seguro
Sin Sistema
共济会
没有estoy Seguro
玛斯·伦塔
马斯拉皮达
没有estoy Seguro
不,不,我是古斯塔里亚
我是古斯塔利亚
努梅罗
这是ViewModel,我删除了部分代码,因为我达到了这里的限制
public class TicketDigitalViewModel : INotifyPropertyChanged
{
public static TimeSpan ServerClientTimeDifference { get; set; }
private bool mostrarErrorQrCode;
private static string surveyUri = "https://sdfghjklfghjkl.com/sadfkljsafdlkjroisdapi/api";
private ClienteViewModel cliente;
private bool isBusy;
private string barCodeResult;
private HubConnection connection;
private IHubProxy ticketHub;
private string connectionID;
private ScreenStatuses screenStatus;
private SampleViewModel encuesta;
private bool isEncuestado;
MobileBarcodeScanner scanner;
bool scannerInitialized = false;
private bool mostrarErrorConexion;
internal void Resume()
{
initConnection();
}
public TicketDigitalViewModel()
{
Encuesta = new SampleViewModel();
ReadQRCodeCommand = new Command(async () =>
await ReadQRCode(),
() => !IsBusy);
SaveSurveyCommand = new Command(async () =>
await SaveSurvey(Encuesta));
CancelSurveyCommand = new Command(async () =>
await CancelSurvey(),
() => !IsBusy);
}
public Command CancelSurveyCommand { get; }
public Command ReadQRCodeCommand { get; }
public Command SaveSurveyCommand { get; }
async Task<ZXing.Result> ReadQRCode()
{
if (!scannerInitialized)
{
scanner = new MobileBarcodeScanner();
scannerInitialized = true;
}
BarCodeResult = null;
var result = await scanner.Scan();
BarCodeResult = result.Text;
return result;
}
#region Data Properties.
public ClienteViewModel Cliente
{
get
{
return cliente;
}
set
{
SetProperty(ref cliente, value);
if (Cliente != null)
{
if (Device.RuntimePlatform == "Windows")
{
Device.StartTimer(TimeSpan.FromSeconds(1),
() =>
{
foreach (var detalle in Cliente.Detalles.Where(p => new string[] { "EnCola", "Atendiendo", "EsperaCliente" }.Contains(p.Estado)))
{
Device.BeginInvokeOnMainThread(() =>
{
detalle.HasTimer = true;
detalle.TiempoTranscurrido = detalle.TiempoTranscurrido.Add(TimeSpan.FromSeconds(1));
});
}
return true;
});
}
else
{
Device.StartTimer(TimeSpan.FromSeconds(1),
() =>
{
foreach (var detalle in Cliente.Detalles.Where(p => new string[] { "EnCola", "Atendiendo", "EsperaCliente" }.Contains(p.Estado)))
{
detalle.HasTimer = true;
detalle.TiempoTranscurrido = detalle.TiempoTranscurrido.Add(TimeSpan.FromSeconds(1));
}
return true;
});
Encuesta.Office = Cliente.PartnerOffice;
Encuesta.Customer = Cliente.Partner;
encuesta.QueueID = Cliente.IdTurno;
}
}
}
}
public SampleViewModel Encuesta
{
get
{
return encuesta;
}
set
{
if (SetProperty(ref encuesta, value))
{
encuesta = value;
OnPropertyChanged();
}
}
}
#endregion
#region Process Properties
internal ScreenStatuses ScreenStatus
{
get
{
return screenStatus;
}
set
{
screenStatus = value;
OnPropertyChanged();
}
}
public string ConnectionUrl
{
get
{
return BarCodeResult == null
? null
: BarCodeResult.Split(new string[] { "/Atencion/Cliente" }, StringSplitOptions.None)[0];
}
}
public string LogoUrl
{
get
{
return BarCodeResult == null
? null
: ConnectionUrl + "/Home/Thumbnail?ImagePath=Logo.png&width=396&height=222";
}
}
public string BarCodeResult
{
get
{
return barCodeResult;
}
set
{
try
{
IsBusy = true;
var theValue = value;
#if DEBUG
theValue = theValue?.Replace("https", "http");
#endif
var scanned = value != null && barCodeResult == null;
if (SetProperty(ref barCodeResult, theValue))
{
if (value == null)
{
Task.Factory.StartNew(() =>
{
UpdateStatus();
});
}
else if (!Uri.IsWellFormedUriString(value, UriKind.Absolute) || !value.Contains("Cliente/TicketDigital/"))
{
BarCodeResult = null;
MostrarErrorQrCode = true;
IsBusy = false;
}
else
{
UpdateStatus();
}
}
if (scanned) Resume();
}
catch (Exception ex)
{
throw;
}
}
}
public bool IsBusy
{
get
{
return isBusy;
}
set
{
if (SetProperty(ref isBusy, value))
{
ReadQRCodeCommand.ChangeCanExecute();
SaveSurveyCommand.ChangeCanExecute();
}
}
}
public string ConnectionID
{
get
{
return connectionID;
}
set
{
connectionID = value;
OnPropertyChanged();
}
}
public bool MostrarBoton
{
get
{
return ScreenStatus == ScreenStatuses.BarCodeScanner;
}
}
public bool MostrarFormularioEncuesta
{
get
{
return ScreenStatus == ScreenStatuses.Survey;
}
}
public bool MostrarAgradecimiento
{
get
{
return ScreenStatus == ScreenStatuses.Finished;
}
}
public bool MostrarServicios
{
get
{
return ScreenStatus == ScreenStatuses.TicketMonitoring;
}
}
public bool IsEncuestado
{
get
{
return isEncuestado;
}
set
{
if (SetProperty(ref isEncuestado, value))
{
}
}
}
public bool MostrarErrorQrCode
{
get
{
return mostrarErrorQrCode;
}
set
{
if (SetProperty(ref mostrarErrorQrCode, value))
{
}
}
}
public bool MostrarErrorConexion
{
get
{
return mostrarErrorConexion;
}
set
{
if (SetProperty(ref mostrarErrorConexion, value))
{
}
}
}
#endregion
#region Methods.
private void initConnection()
{
if (barCodeResult != null)
{
if (Device.RuntimePlatform == "Windows")
{
IsBusy = true;
connection = new HubConnection(ConnectionUrl + "/signalr/hubs");
AsyncHelpers.RunSync(MonitorTicket);
IsBusy = false;
}
else
{
IsBusy = true;
connection = new HubConnection(ConnectionUrl + "/signalr/hubs");
Task.Factory.StartNew(async () =>
{
await MonitorTicket();
IsBusy = false;
});
}
}
else
{
if (connection != null)
connection.Dispose();
}
}
async Task MonitorTicket()
{
Cliente = await this.HttpRequest<ClienteViewModel>(HttpMethod.Get,
"/TurnoDetalleApi/DatosTicketImpresion",
string.Format("id={0}",
BarCodeResult.Split(new string[] { "id=" },
StringSplitOptions.None)[1])
);
ticketHub = connection.CreateHubProxy("TicketHub");
ticketHub.On<bool>("isAlive", (alive) =>
{
});
ticketHub.On<ClienteDetalleViewModel>("update", async (detalle) =>
{
if (detalle.Servicio == null)
{
try
{
detalle.Servicio = await this.HttpRequest<string>(HttpMethod.Get, "/ServicioApi/GetNombreServicio", $"IdServicio={detalle.IdServicio}");
detalle.SalaEspera = await this.HttpRequest<string>(HttpMethod.Get, "/SalaEsperaApi/GetNombre/", $"id={detalle.IdSalaEspera}");
}
catch (WebException)
{
BarCodeResult = null;
MostrarErrorConexion = true;
}
}
if (Cliente.Detalles
.Where(p => p.IdServicio == detalle.IdServicio)
.Any())
{
var miDetalle = Cliente.Detalles.Last(p => p.IdServicio == detalle.IdServicio);
miDetalle.Servicio = detalle.Servicio;
miDetalle.SalaEspera = detalle.SalaEspera;
miDetalle.Estado = detalle.Estado;
miDetalle.TiempoAtencionPromedio = detalle.TiempoAtencionPromedio;
miDetalle.TiempoEsperaRestante = detalle.TiempoEsperaRestante;
miDetalle.TotalEnCola = detalle.TotalEnCola;
miDetalle.TiempoTranscurrido = detalle.TiempoTranscurrido;
}
else
{
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
detalle.HasTimer = true;
detalle.TiempoTranscurrido = detalle.TiempoTranscurrido.Add(TimeSpan.FromSeconds(1));
return true;
});
Cliente.Detalles.Add(detalle);
}
UpdateStatus();
});
await connection.Start();
ConnectionID = connection.ConnectionId;
var sample = await NetworkHelper.HttpRequest<SampleViewModel>("https://sdfghjklfghjkl.com/sadfkljsafdlkjroisdapi/api", HttpMethod.Get, "/survey", $"QueueID={Cliente.IdTurno}&Customer={Cliente.Partner}");
IsEncuestado = sample != null;
await ticketHub.Invoke("SetTicket", Cliente.IdTurno);
await Task.Factory.StartNew(async () =>
{
do
{
await ticketHub.Invoke("KeepAlive");
await Task.Delay(1000 * 60);
} while (ScreenStatus == ScreenStatuses.TicketMonitoring);
});
IsBusy = false;
MostrarErrorConexion = false;
}
private void UpdateStatus()
{
if (BarCodeResult == null)
{
ScreenStatus = ScreenStatuses.BarCodeScanner;
}
else if (Cliente != null && Cliente.Detalles.Any(p => new string[] { "EnCola", "Atendiendo", "EsperaCliente" }.Contains(p.Estado)) && !IsEncuestado)
{
OnPropertyChanged(nameof(LogoUrl));
ScreenStatus = ScreenStatuses.TicketMonitoring;
}
else if (Cliente == null)
{
ScreenStatus = ScreenStatuses.TicketMonitoring;
}
else if (!IsEncuestado)
{
ScreenStatus = ScreenStatuses.Survey;
}
else
{
ScreenStatus = ScreenStatuses.Finished;
}
OnPropertyChanged(nameof(ScreenStatus));
OnPropertyChanged(nameof(MostrarAgradecimiento));
OnPropertyChanged(nameof(MostrarBoton));
OnPropertyChanged(nameof(MostrarFormularioEncuesta));
OnPropertyChanged(nameof(MostrarServicios));
IsBusy = false;
}
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
公共类TicketDigitalViewModel:INotifyPropertyChanged
{
公共静态TimeSpan服务器ClientTimeDifference{get;set;}
私有布尔mostrarErrorQrCode;
私有静态字符串surveyUri=”https://sdfghjklfghjkl.com/sadfkljsafdlkjroisdapi/api";
私人客户;模型客户;
私人厕所很忙;
私有字符串条码结果;
专用连接;
私人iHubThub;
私有字符串连接ID;
私有屏幕状态屏幕状态;
私有样本视图模型encuesta;
私立学校;
手机条码扫描仪;
bool scannerInitialized=false;
私人住宅;
内部无效恢复()
{
initConnection();
}
公开票证DigitalViewModel()
{
Encuesta=新的SampleViewModel();
ReadQRCodeCommand=新命令(异步()=>
等待ReadQRCode(),
()=>!我很忙);
SaveSurveyCommand=new命令(异步()=>
等待储蓄调查(Encuesta));
CancelSurveyCommand=新命令(异步()=>
等待取消调查(),
()=>!我很忙);
}
公共命令CancelSurveyCommand{get;}
公共命令ReadQRCodeCommand{get;}
公共命令SaveSurveyCommand{get;}
异步任务ReadQRCode()
{
如果(!scannerInitialized)
{
scanner=新的MobileBarcodeScanner();
scannerInitialized=true;
}
条形码结果=空;
var result=wait scanner.Scan();
BarCodeResult=result.Text;
返回结果;
}
#区域数据属性。
公共客户视图模型客户
{
得到
{
回头客;
}
设置
{
SetProperty(参考客户,值);
如果(客户!=null)
{
如果(Device.RuntimePlatform==“Windows”)
{
设备启动计时器(时间跨度从秒开始(1),
() =>
{
foreach(Cliente.Detalles.Where(p=>newstring[]{“EnCola”、“Atendiendo”、“EsperaCliente”}.Contains(p.Estado)))
{
Device.beginInvokeMainThread(()=>