xamarin - “后期绑定”期间的数据在真机上不显示(Xamarin.Forms + Prism + CarouselViewController)
问题描述
你好!我在下面给出的代码在 IOS 模拟器上运行良好,但在真实设备(Iphone 6S Plus)上不起作用 - 标签集合(在我的情况下是什么 - 你再看)没有填写。(Xamarin.Forms、IOS 项目、Prism、CarouselViewController)
我提前为大量代码道歉 - 这是正在开发的大型程序的一部分,我立即决定带来所有必要的清单。
1.有PageA/PageAViewModel
(linked BindableBase(Prism))、PageB/PageBViewModel
(linked BindableBase(Prism))和logical ViewModelС
。在PageAViewModel
逻辑ViewModelС
上创建并PageBViewModel
作为导航参数传输:
async Task GoPageB()
{
var navigationParams = new NavigationParameters();
navigationParams.Add("ViewModelС", ViewModelС);
await NavigationService.NavigateAsync(new System.Uri("http://.../PageB",
System.UriKind.Absolute), navigationParams);
}
2.在执行代码的过程中,被收集PageB
,然后它的PageBViewModel
,然后PageB
计算出接收导航参数的方法,其中PageBViewModel
接收的是ViewModelC
:
public override void OnNavigatingTo(INavigationParameters parameters)
{
var modelInParameters = parameters["ViewModelC"] as ViewModelC;
MyViewModelC = modelInParameters;
}
3.ViewModelC
作为属性存在,而在PageBViewModel
构造函数中不声明,主要在OnNavigatingTo
方法中获取和赋值
public ViewModelC MyViewModelC
{
get => _myViewModelC;
set => SetProperty(ref _myViewModelC, value);
}
4.PageB/PageBViewModel
实际上是基于CarouselViewControler
( https://github.com/alexrainman/CarouselView ) 的入职培训。在 XAML 中,它看起来像这样:
<ContentPage.Content>
<abstractions:CarouselViewControl x:Name="OnBrdngPg_CrslVwCntrl"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Orientation="Horizontal"
InterPageSpacing="0"
IsSwipeEnabled="True"
IndicatorsTintColor="{StaticResource ClrGreyLight}"
CurrentPageIndicatorTintColor="{StaticResource ClrLightorange}"
AnimateTransition="True"
Position="0"
ShowIndicators="True"
ShowArrows="False">
<abstractions:CarouselViewControl.ItemsSource>
<x:Array Type="{x:Type ContentView}">
<ContentView x:Name="CW1"/>
<ContentView x:Name="CW2"/>
<ContentView x:Name="CW3"/>
<ContentView x:Name="CW4"/>
<ContentView x:Name="CW5"/>
</x:Array>
</abstractions:CarouselViewControl.ItemsSource>
</abstractions:CarouselViewControl>
</ContentPage.Content>
5.CarouselViewControl
中x:Array
包括五个ContentViews
。每个ContentView
都有五种视图变体(Statecontainer 的实现 - 一页的五种状态 Normal、Loading、Error、NoInternet、NoData - 页面状态根据程序逻辑在代码中设置,在 XAML 中 Statecontainer 订阅状态改变并显示相应的ContentView
:
<ContentView x:Name="CW2"
Style="{DynamicResource ContentViewBoardingStyle}"
BackgroundColor="{StaticResource ClrGeneralwhite}">
<ContentView.Content>
<Grid BackgroundColor="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.Children>
<StackLayout Grid.Row="0"
Style="{StaticResource StLt_BaseStyle}">
<StackLayout.Children>
<Images:ImageFit Source="{Binding HeaderImageSource}"/>
</StackLayout.Children>
</StackLayout>
<stateContainer:StateContainer State="{Binding OnBoardingInState}"
Grid.Row="1"
Style="{StaticResource StateContainerNormalStateStyle}"
BackgroundColor="{StaticResource ClrGeneralwhite}">
<stateContainer:StateCondition State="Normal">
<stateContainer:StateCondition.Content>
<StackLayout x:Name="OnbdngPg_RootStack2"
Orientation="Vertical"
Spacing="12">
<StackLayout.Children>
<StackLayout Padding="0,15,0,10">
<StackLayout.Children>
<labels:LblLvl2 Text="{markupExtension:Translate OnBrdPg_Pg2_HdrTxt}"
TextColor="{StaticResource ClrGeneraldark}"
HorizontalTextAlignment="Start"/>
</StackLayout.Children>
</StackLayout>
<StackLayout>
<StackLayout.Children>
<custom:GdyStackPanel x:Name="CustomControl"
CustomViewModel="{Binding ViewModelC, Mode=OneTime}"/>
</StackLayout.Children>
</StackLayout>
</StackLayout.Children>
</StackLayout>
</stateContainer:StateCondition.Content>
</stateContainer:StateCondition>
<stateContainer:StateCondition State="Error"/>
<stateContainer:StateCondition State="Loading"/>
<stateContainer:StateCondition State="NoInternet"/>
<stateContainer:StateCondition State="NoData"/>
</stateContainer:StateContainer>
</Grid.Children>
</Grid>
</ContentView.Content>
</ContentView>
6. 正如您在 上看到的CW2
,有一个CustomControl
- 这是一个自定义的Grid
,除其他外,有一个标签云 - 它从 中生成的按钮的集合ObservableCollection CustomControlTagsCollection
,位于ViewModelC
(在控制中它是 BindablePropertyCustomViewModel
)。
public static readonly BindableProperty CustomViewModelProperty = BindableProperty.Create(
nameof(CustomViewModel),
typeof(ViewModelC),
typeof(CustomControl),
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
Device.BeginInvokeOnMainThread(() =>
{
var panel = bindable as CustomControl;
var oldbinding = oldValue as ViewModelC;
var newbinding = newValue as ViewModelC;
if (oldbinding == null)
{
panel.CustomViewModel = newbinding;
panel.ButtonNewTag.BindingContext = newbinding;
panel.EntryNewTag.BindingContext = newbinding;
}
// This method collects the tag cloud from the collection.
panel.CreateStackPanelAsync();
});
});
public ViewModelC CustomViewModel
{
get => (ViewModelC)GetValue(CustomViewModelProperty);
set => SetValue(CustomViewModelProperty, value);
}
概括
总结一下,我们可以这么说:
PageA/PageAViewModel
传输ViewModelC
,PageB/PageBViewModel
它接收ViewModelC
作为“导航参数”的方法OnNavigatingTo
(最初在构造函数PageBViewModel
ViewModelC
中未定义PageBViewModel
为最初初始化的公共属性PageBViewModel
并且在OnNavigatingTo
方法中)。出于这个原因,PageB/PageBViewModel
最初建造时没有ViewModelС
- 分别
PageB/PageBViewModel
→→CarouselViewControler
_ContentView x:Name:"CW2"
在CustomControl
初始化时收到一个空CustomControlTagsCollection
标签云不会 - 当
PageB/PageBViewModel
接收时ViewModelС
,沿着路径PageB/PageBViewModel
→CarouselViewController
->ContentView x:Name="CW2"
→CustomControl
接收传输的ViewModelС
,它执行propertyChanged BindableProperty CustomViewModelProperty
,绑定被更新并且panel.CreateStackPanelAsync ()
调用方法,用标签填充集合。从某种意义上说,这种“后期绑定”。
我将不胜感激任何帮助。
我为谷歌翻译道歉。
给你们所有人(我们 :))好的和干净的代码!
解决方案
你好!
我在使用 Prism 的背景下解决了我的问题:
我用 替换了逻辑模型
ViewModelC
,ServiceC
同时我创建IServiceC
并ServiceC
注册了它们App.xaml.cs
:containerRegistry.Register<IServiceC, ServiceC>();
ViewModelC 的所有工作逻辑都转移到
ServiceC
.感兴趣的处理
ServiceC
数据的 ViewModel 实现了它://Declaration private IServiceC _serviceC; //Initialization public ViewModelB(ServiceC serviceC) { __serviceC = serviceC; }
在 ViewModels 中,
ServiceC
需要通过 xaml 进行绑定,这样实现它(不确定这在安全性方面是否正确)://宣言 私有 IServiceC _serviceC; 公共 IServiceC 服务C { 得到 => _serviceC; 设置 => 设置属性(参考 _serviceC,值); } //初始化 公共 ViewModelB(ServiceC serviceC) { 服务 C = 服务 C; }
CustomControl 中的 BindableProperty:
public static readonly BindableProperty serviceCProperty = BindableProperty.Create( nameof(MyServiceC), typeof(ServiceC), typeof(CustomControl), null, BindingMode.OneTime, propertyChanged: (bindable, oldValue, newValue) => { var panel = bindable as CustomControl;
public ServiceC MyServiceC { get => (ServiceC)GetValue(ServiceCProperty ); set => SetValue(serviceCProperty, value); }Device.BeginInvokeOnMainThread(() => { var oldbinding = oldValue as ServiceC; var newbinding = newValue as ServiceC; if (oldbinding == null) { panel.MyServiceC = newbinding; panel.ButtonNewTag.BindingContext = newbinding; panel.EntryNewTag.BindingContext = newbinding; //This is where the panel is filled with tags panel.CreateStackPanelAsync(); } }); });
- 退出视图模型时,执行 Destroy 方法(为了避免内存泄漏):
public override void Destroy() { base.Destroy(); this.ServiceC = null; }
- 退出视图模型时,执行 Destroy 方法(为了避免内存泄漏):
结果- 在模拟器和真实设备上一切正常。
调查结果:
我意识到,在使用 Prism 并设计与第三方基本实体的 view/viewmodels 数据交换逻辑时,没有必要尝试通过在 viewmodels (
MyClass myClass = new MyClass () {}
) 中声明的类来实现这些实体,然后传递链接或克隆视图模型之间的此类 - 这会导致其中一个阶段的数据混乱和可能的丢失(及时欠载)。如果我对 Prism 中服务的安全性和性能的进一步研究证实了稳定和节省资源的工作假设,我推荐这种方式。
我将不胜感激有关此事的任何建议、意见和建议。
谢谢你们!
推荐阅读
- css - 将appBar放在页面底部
- twitter-bootstrap - Next.js 中的引导轮播
- c# - 如何使用 DisplayFormat 将小数点逗号更改为指向 c#?
- node.js - 从 gmail api 在 Web 应用程序中显示电子邮件
- python - Django 模板块没有出现在渲染模板中的正确位置 - 导致 jQuery“$ 未定义”错误
- android - 如何解决 PreferredSize 颤振中的零参数构造函数错误?
- ajax - 如何在 Laravel 的 Ajax 请求中手动验证 CSRF 令牌
- elasticsearch - 如何在 ElasticSearch 中搜索包含错误单词的短语?
- powerbi - 使用 React 包装器嵌入 Power BI 报表时,报表中的一些视觉对象未呈现
- amazon-s3 - 从 S3 存储桶加载 pytorch 模型