如何在 Xamarin Forms 的自定义控件中添加视图?

How to add a View in Custom Control in Xamarin Forms?

我有一个自定义控件 LoadingPanel,它有一个 ActivityIndicator 和一个 Label。我想从控制之外的任何地方访问这个 activity 指示器。只是我想改变它的 IsRunning 状态。我可以使用 bool IsActivityIndicatorRunning 做到这一点,它 运行 很好,但我不想对 ActivityIndicator 的每个 属性 重复这样做,因此我想添加视图并使用其属性。因此,我在自定义控件中有 ActivityIndicator,并希望将其映射到控件的 XAML 代码中存在的 ActivityIndicator

这是我的自定义控件 LoadingPanel.xaml:

<StackLayout Orientation="Horizontal">
    <ActivityIndicator x:Name="activityIndicator" />
    <Label x:Name="loadingMessage" />
</StackLayout>

这是我的自定义控件背后的代码:

public static readonly BindableProperty IsActivityIndicatorRunningProperty = BindableProperty.Create(nameof(IsActivityIndicatorRunning), typeof(bool), typeof(LoadingPanel), false, BindingMode.TwoWay, propertyChanged: IsActivityIndicatorRunningPropertyChanged);
public static readonly BindableProperty ActivityIndicatorProperty = BindableProperty.Create(nameof(ActivityIndicator), typeof(ActivityIndicator), typeof(LoadingPanel), propertyChanged: ActivityIndicatorPropertyChanged);

public bool IsActivityIndicatorRunning { get => (bool)GetValue(IsActivityIndicatorRunningProperty); set => SetValue(IsActivityIndicatorRunningProperty, value); }
public ActivityIndicator ActivityIndicator { get => (ActivityIndicator)GetValue(ActivityIndicatorProperty); set => SetValue(ActivityIndicatorProperty, value); }

public static void IsActivityIndicatorRunningPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var control = (LoadingPanel)bindable;
    control.activityIndicator.IsRunning = (bool)newValue;    // just remember this, continue ahead, till here working fine, just revise these concepts
}

public static void ActivityIndicatorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var control = (LoadingPanel)bindable;
    control.activityIndicator = (ActivityIndicator)newValue;
}

这是我使用自定义控件的地方

<customControls:LoadingPanel x:Name="loadingPanel" />

我使用自定义控件的隐藏代码

async void ChangeState(object sender, EventArgs e)
{
    loadingPanel.IsActivityIndicatorRunning = true; // This is working fine
    await Task.Delay(5000);

    // here I am getting NullReferenceException as it cannot find ActivityIndicator
    loadingPanel.ActivityIndicator.IsRunning = false;
}

无需在 XAMLC# 代码隐藏 中声明字段(控件或视图)。在其中任何一个中声明。无论您在何处声明字段,请将它们设为 public,以便可以从您的自定义控件外部访问它们。

请注意,在 XAML 中声明的字段、控件或视图在默认情况下不是 public。与 C# 相同 Class 默认情况下属性、对象、字段、控件是私有的。

您可以直接从外部使用您的自定义控件的子视图,如果它们是 public。正如您在 XAML 中所做的那样,将其声明为:

<StackLayout Orientation="Horizontal">
    <ActivityIndicator x:Name="ActivityIndicator" x:FieldModifier="public" />
    <Label x:Name="LoadingMessage" x:FieldModifier="public" />
</StackLayout>
// this should work now from outside of your custom control
loadingPanel.ActivityIndicator.IsRunning = false;

注意你有 x:Name="activityIndicator"(小写),但你试图使用 loadingPanel.ActivityIndicator(大写)。

另请注意,您不会直接在控件上使用数据绑定,而是在该控件的属性上使用绑定,例如 Label 的 TextIsVisible 属性, ActivityIndicatorIsRunning 属性 等。因此请从您的代码中删除这些内容:

// Remove this if you are already declaring ActivityIndicator in XAML
public ActivityIndicator ActivityIndicator { get => (ActivityIndicator)GetValue(ActivityIndicatorProperty); set => SetValue(ActivityIndicatorProperty, value); }

// Remove this as it is not required for Controls directly
public static readonly BindableProperty ActivityIndicatorProperty = BindableProperty.Create(nameof(ActivityIndicator), typeof(ActivityIndicator), typeof(LoadingPanel), propertyChanged: ActivityIndicatorPropertyChanged);

// Remove this
public static void ActivityIndicatorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    var control = (LoadingPanel)bindable;
    control.activityIndicator = (ActivityIndicator)newValue;
}