作为一个经验不足的Xamarin
开发人员,我试图从ContentView
我的父页面 () 中的子页面 () 中检索属性值ContentPage
。我可以找到一些如何从父页面获取/设置值到子页面的示例,但反之则不然。
更多细节:
在我的ContentPage
我有一个CarouselView
,这CarouselView
有一个DataTemplate
包含一个ContentView
,这个 ContentView 里面还有一个 CarouselView,它有 2 层/2 个垂直轮播项目。
当 CarouselView 在 ContentView(子页面)内的位置,改变位置到第二项时,IndicatorView
在父页面中的 应该设置为invisible
。
我对使用 a 的经验并不多,BindableProperty
但我认为这是要走的路。我现在设置如下:
父页面/内容页面:
<local:ExtendedCarouselView
x:Name="carousel"
HorizontalScrollBarVisibility="Never"
IndicatorView="activityIndicatorView"
IsScrollAnimated="False"
ItemsSource="{Binding ActivityData}"
Position="{Binding Position, Mode=TwoWay}"
VerticalOptions="FillAndExpand">
<local:ExtendedCarouselView.ItemTemplate>
<DataTemplate>
<Frame Style="{StaticResource CarouselWorkaround}">
<local:PCSActivityOverviewTemplate x:Name="testy" />
</Frame>
</DataTemplate>
</local:ExtendedCarouselView.ItemTemplate>
</local:ExtendedCarouselView>
<IndicatorView
x:Name="activityIndicatorView"
Padding="0,0,0,30"
IndicatorColor="{DynamicResource TranslucidBlack}"
IsVisible="{Binding InnerCarouselViewPosition, Converter={StaticResource IndicatorVisibilityConverter}, Mode=TwoWay}"
SelectedIndicatorColor="{DynamicResource BaseTextColor}"
VerticalOptions="Start" />
子页面/内容视图(XAML):
<ContentView.Content>
<CarouselView
x:Name="carousel"
ItemsSource="{Binding ., Converter={StaticResource OneToManyConverter}, ConverterParameter=2}"
VerticalOptions="FillAndExpand"
VerticalScrollBarVisibility="Never"
PositionChanged="carousel_PositionChanged"> <!-- The event which should change the property 'InnerCarouselViewPosition' -->
<CarouselView.ItemTemplate>
<grial:IntMemberTemplateSelector MemberName="Position">
<grial:IntMemberTemplateSelector.Items>
<!-- CAROUSEL'S PAGE 0 -->
<grial:IntMemberTemplateSelectorItem Value="0">
<DataTemplate>
<!-- Other elements... -->
</DataTemplate>
</grial:IntMemberTemplateSelectorItem>
<!-- CAROUSEL'S PAGE 1 -->
<grial:IntMemberTemplateSelectorItem Value="1">
<DataTemplate>
<!-- Other elements... -->
</DataTemplate>
</grial:IntMemberTemplateSelectorItem>
</grial:IntMemberTemplateSelector.Items>
</grial:IntMemberTemplateSelector>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentView.Content>
内容视图(C#/.cs):
public partial class PCSActivityOverviewTemplate : ContentView
{
public static BindableProperty CurrentChildCarouselViewLocationProperty =
BindableProperty.Create(
nameof(CurrentChildCarouselViewLocationProperty),
typeof(int),
typeof(CarouselView),
defaultValue: 1);
public int CurrentChildCarouselViewLocation
{
get { return (int)GetValue(CurrentChildCarouselViewLocationProperty); }
set { SetValue(CurrentChildCarouselViewLocationProperty, value); }
}
private void carousel_PositionChanged(object sender, PositionChangedEventArgs e)
{
CarouselView _carouselView = (CarouselView)sender;
CurrentChildCarouselViewLocationProperty = _carouselView.Position;
}
... code omitted
}
当内部轮播视图位置发生变化时,bindable property
应设置,此属性应在父页面中使用转换器设置指示器视图可见/不可见(位置 0 = 可见,位置 1 = 不可见)。对于某些人来说,可能是一个非常明显的原因,上面的方法不起作用。
可见性转换器:
public class CarouselIndicatorVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 0 : 1;
}
}
更新*
我还尝试在我的 ViewModel 中使用绑定作为位置属性,虽然绑定值发生了变化,但我无法在父页面中访问它,没有任何反应,转换器没有被触发),我删除了可绑定属性。
新的内容页面 XAML(父轮播):
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
...
>
<ContentPage.Resources>
<ResourceDictionary>
<local:CarouselIndicatorVisibilityConverter x:Key="IndicatorVisibilityConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid>
<Grid>
<local:ExtendedCarouselView
x:Name="carousel"
HorizontalScrollBarVisibility="Never"
IndicatorView="activityIndicatorView"
IsScrollAnimated="False"
ItemsSource="{Binding ActivityData}"
Position="{Binding Position, Mode=TwoWay}"
VerticalOptions="FillAndExpand">
<local:ExtendedCarouselView.ItemTemplate>
<DataTemplate>
<Frame Style="{StaticResource CarouselWorkaround}">
<local:PCSActivityOverviewTemplate x:Name="testy" />
</Frame>
</DataTemplate>
</local:ExtendedCarouselView.ItemTemplate>
</local:ExtendedCarouselView>
<IndicatorView
x:Name="activityIndicatorView"
Padding="0,0,0,30"
IndicatorColor="{DynamicResource TranslucidBlack}"
IsVisible="{Binding BindingContext.CurrentChildCarouselViewLocation, Source={x:Reference carousel}, Converter={StaticResource IndicatorVisibilityConverter}, Mode=TwoWay}"
SelectedIndicatorColor="{DynamicResource BaseTextColor}"
VerticalOptions="Start" />
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>
子页面的 XAML:
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
...
>
<ContentView.Content>
<CarouselView
x:Name="carousel"
IsBounceEnabled="False"
ItemsSource="{Binding ., Converter={StaticResource OneToManyConverter}, ConverterParameter=2}"
Position="{Binding CurrentCarouselViewLocation}"
PositionChanged="carousel_PositionChanged"
VerticalOptions="FillAndExpand"
VerticalScrollBarVisibility="Never">
<CarouselView.ItemsLayout>
<LinearItemsLayout
ItemSpacing="0"
Orientation="Vertical"
SnapPointsAlignment="Start"
SnapPointsType="MandatorySingle" />
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<grial:IntMemberTemplateSelector MemberName="Position">
<grial:IntMemberTemplateSelector.Items>
<!-- CAROUSEL'S PAGE 0 -->
<grial:IntMemberTemplateSelectorItem Value="0">
<DataTemplate>
.. more elements omitted
</DataTemplate>
</grial:IntMemberTemplateSelectorItem>
<!-- CAROUSEL'S PAGE 1 -->
<grial:IntMemberTemplateSelectorItem Value="1">
<DataTemplate>
.. more elements omitted
</DataTemplate>
</grial:IntMemberTemplateSelectorItem>
</grial:IntMemberTemplateSelector.Items>
</grial:IntMemberTemplateSelector>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentView.Content>
</ContentView>
视图模型
namespace PCS2.APP.ViewModels
{
public class ActivityOverviewViewModel : ObservableObject
{
private List<ActivityLocation> activityData;
private readonly IRoutingService _routingService;
private double _screenOpacity;
private bool _showLoadingAnimation;
private int? _clientId;
private int _position;
private int _innerCarouselPosition;
// Position of the Parent page CarouselView
public int Position
{
get { return _position; }
set { SetProperty(ref _position, value); }
}
// Data source for the child data
public List<ActivityLocation> ActivityData
{
get { return activityData; }
set { SetProperty(ref activityData, value); }
}
public double ScreenOpacity
{
get { return _screenOpacity; }
set { SetProperty(ref _screenOpacity, value); }
}
public bool ShowLoadingAnimation
{
get { return _showLoadingAnimation; }
set { SetProperty(ref _showLoadingAnimation, value); }
}
public ActivityOverviewViewModel(int? clientId = null, IRoutingService routingService = null)
: base(listenCultureChanges: true)
{
_clientId = clientId;
_routingService = routingService ?? Locator.Current.GetService<IRoutingService>();
LoadData();
}
private async void LoadData()
{
try
{
ShowLoadingAnimation = true;
ScreenOpacity = 0.1;
// Getting the data
var _activitiesData = await App.Database.GetActivityDataAsync(_clientId, DateTime.UtcNow);
ActivityData = _activitiesData;
}
catch (Exception ex)
{
throw;
}
finally
{
ShowLoadingAnimation = false;
ScreenOpacity = 1.0;
}
}
}
}