Xamarin Forms FindByName始终返回null

时间:2020-05-14 07:24:09

标签: c# xamarin syncfusion

我有一个绑定到视图模型的ContentPage。仍然有一点,我需要访问StackLayout内的Picker,而后者又位于Syncfusion ListViewItem中。 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:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sf="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             mc:Ignorable="d"
             x:Class="PerformanceTM.Views.NewCircuitView">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Welcome to Xamarin.Forms!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
            <sf:SfListView x:Name="ExerciseList" ItemsSource="{Binding Exercises}" DragStartMode="OnHold">
                <sf:SfListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Horizontal">
                                <Picker Title="Kategorie" x:Name="CategoryPicker" ItemsSource="{Binding Source={x:Reference ExerciseList}, Path=BindingContext.ExerciseCategories}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding Category}" SelectedIndexChanged="CategoryChanged"/>
                                <Picker Title="Übung" x:Name="ExerciseNamePicker" ItemDisplayBinding="{Binding Name}" SelectedIndexChanged="ExerciseSelected"/>
                                <Button Text="..." Clicked="ConfigureSetsClicked"/>
                                <Button Text="(-)" />
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </sf:SfListView.ItemTemplate>
            </sf:SfListView>
            <StackLayout Orientation="Horizontal">
            <Button Text="(+) Übung" Command="{Binding AddExerciseCommand}"/>
            <Button Text="Ok" Command="{Binding ApplyChangesCommand}"/>
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

如您所见,ViewCell中的两个Picker都分配了x:Name。当我在ExerciseCategoryPicker中选择一个值时,我会在后面的代码中加载新值并将其分配给ExerciseNamePicker,如下所示:

    private async void CategoryChanged(object sender, EventArgs e)
    {
        var picker = sender as Picker;
        var stackLayout = picker.Parent as StackLayout;
        ListViewItem listViewItem = stackLayout.Parent as ListViewItem;

        var ex = picker.BindingContext as Exercise;
        if (ex is null)
            return;

        ex.Category = picker.SelectedItem as ExerciseCategory;

        var apiService = new ApiServices();
        var exsForCategory = await apiService.GetExercisesForCategory(ex.Category.Name);

        Picker exnp = stackLayout.FindByName<Picker>("ExerciseNamePicker");
        if (exnp is null)
            exnp = stackLayout.Children.OfType<Picker>().Where(x => x.Title == "Übung").FirstOrDefault();

        exnp.ItemsSource = exsForCategory;
        if (exsForCategory.Count > 0)
            exnp.SelectedItem = exsForCategory.FirstOrDefault();

        var bc = this.BindingContext as NewCircuitViewModel;
        bc.ExercisePairing.Descriptor = bc.ExercisePairing.UpdateDescriptor();
    }

private void ExerciseSelected(object sender, EventArgs e)
    {
        try
        {
            var picker = (sender as Picker);
            var stackLayout = picker.Parent as StackLayout;
            var vc = picker.Parent.Parent as Syncfusion.ListView.XForms.ListViewItem;
            var ex = vc.BindingContext as Exercise;
            var se = picker.ItemsSource[picker.SelectedIndex] as Exercise;

            var exnp = stackLayout.FindByName("CategoryPicker") as Picker;
            if (exnp is null)
                exnp = stackLayout.Children.OfType<Picker>().Where(x => x.Title == "Kategorie").FirstOrDefault();

            var ec = exnp.SelectedItem as ExerciseCategory;

            ex.Category = ec;
            ex.Name = se.Name;
            ex.Id = se.Id;
            ex.Description = se.Description;
            ex.VideoUrl = se.VideoUrl;

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

现在发生的是,在每种情况下FindByName()返回null。奇怪的是,当我在调用FindByName之前调试并检查StackLayout的子代时,它确实包含具有适当ID(即x:Name)的子代。当我通过get访问它们时,我得到了GUID(这使我感到困惑,因为我认为首先应该只包含一个GUID,但是很好)。

我已经找到了一种解决方法,只需按Title选择元素,但这是一个相当奇怪的行为,尤其是考虑到过去已经奏效。从那时起,我所做的唯一更改就是SyncFusion ListView的集成。这可能是个问题吗?有没有人经历过和/或可以提供更多见识?

PS:我已经完成了所有“常规”修复,例如删除.v,bin和obj文件夹...

1 个答案:

答案 0 :(得分:0)

您可以使用对ItemTemplate父元素的行为来获取 SfListView.ItemTemplate 的子元素。请参考以下代码片段,以获取DataTemplate中的命名元素,

Xaml :定义StackLayout的行为

<sf:SfListView x:Name="ExerciseList" ItemsSource="{Binding Exercises}" DragStartMode="OnHold">
<sf:SfListView.ItemTemplate>
    <DataTemplate>
        <ViewCell>
            <StackLayout Orientation="Horizontal">
                <StackLayout.Behaviors>
                    <local:Behavior/>
                </StackLayout.Behaviors>

                <Picker Title="Kategorie" x:Name="CategoryPicker" ItemsSource="{Binding Source={x:Reference ExerciseList}, Path=BindingContext.ExerciseCategories}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding Category}"/>
                <Picker Title="Übung" x:Name="ExerciseNamePicker" ItemDisplayBinding="{Binding Name}"/>
                <Button Text="..." Clicked="ConfigureSetsClicked"/>
                <Button Text="(-)" />
            </StackLayout>
        </ViewCell>
    </DataTemplate>
</sf:SfListView.ItemTemplate>

行为:使用FindByElement获取元素。触发Picker的SelectedIndexChanged事件。

public class Behavior : Behavior<StackLayout>
{
    Picker CategoryPicker;
    Picker ExerciseNamePicker;

    protected override void OnAttachedTo(StackLayout bindable)
    {
        CategoryPicker = bindable.FindByName<Picker>("CategoryPicker");
        ExerciseNamePicker = bindable.FindByName<Picker>("ExerciseNamePicker");

        CategoryPicker.SelectedIndexChanged += CategoryPicker_SelectedIndexChanged;
        ExerciseNamePicker.SelectedIndexChanged += ExerciseNamePicker_SelectedIndexChanged;

        base.OnAttachedTo(bindable);
    }

    private void ExerciseNamePicker_SelectedIndexChanged(object sender, EventArgs e)
    {
        //Your logic here.
    }

    private void CategoryPicker_SelectedIndexChanged(object sender, EventArgs e)
    {
        //Your logic here.
    }
}

您还可以从以下链接中参考我们的在线文档, Document