Xamarin Picker 在 UI 上显示不需要的元素

Xamarin Picker showing undesirable elements on UI

在这一点上拔头发。如果启用,我的选择器在 UI and/or 的选择器标题 属性 上显示一条烦人的线。我只是想要选择器,而不是显示在其下方 UI 上的内容。关于如何实现这一目标的任何想法?我必须使用自定义渲染器还是缺少一些简单的东西?

注意:以下示例中的列表有意为空。

没有标题,我点击Existing按钮,线条出现,再次点击出现模态:

有了标题,我点击现有按钮,显示行和标题,再次点击它,出现模态:

不知道为什么我必须点击按钮两次。但它只是在初始页面加载时。如果我退出模态并再次点击按钮,它立即出现,没有double-click。不确定这是否与我最初的问题有关,但我认为我会将其包括在内以获取更多信息。

NewSubjectPage.xaml(为简洁起见截断)

<ContentPage.Content>
    <StackLayout x:Name="NewSubjectMainLay">
        <ScrollView>
            <StackLayout x:Name="NewSubjectChildLay">
                <Grid>
                    <Button 
                        x:Name="NewSubjectExisChrtBtn" 
                        Clicked="NewSubjectExisChrtBtn_Clicked"
                        Grid.Column="2"
                        Text="Existing" />
                </Grid>
            </StackLayout>
        </ScrollView>
        <Picker 
            x:Name="NewSubjectExisChrtPck"
            IsVisible="False"
            ItemsSource="{Binding Charts}"
            ItemDisplayBinding="{Binding Name}"
            SelectedIndexChanged="NewSubjectExisChrtPck_SelectedIndexChanged"
            Title="Select chart"
            Unfocused="NewSubjectExisChrtPck_Unfocused"/>
    </StackLayout>
</ContentPage.Content>

NewSubjectPage.xaml.cs(为简洁起见截断)

public partial class NewSubjectPage : ContentPage
{
    private string chartName;
    private readonly NewSubjectViewModel _viewModel;

    public string ChartName
    {
        get => chartName;
        private set
        {
            chartName = value;
            OnPropertyChanged();
        }
    }

    public NewSubjectPage()
    {
        InitializeComponent();

        BindingContext = _viewModel = new NewSubjectViewModel();

        chartName = "";
    }

    private void NewSubjectExisChrtBtn_Clicked(object sender, EventArgs e)
    {
        _viewModel.LoadChartsCommand.Execute(null);
        NewSubjectExisChrtPck.IsVisible = true;
        NewSubjectExisChrtPck.Focus();
    }

    private void NewSubjectExisChrtPck_SelectedIndexChanged(object sender, EventArgs e)
    {
        var picker = (Picker)sender;
        int selectedIndex = picker.SelectedIndex;

        if (selectedIndex != -1)
        {
            ChartName = picker.Items[picker.SelectedIndex];
        }
    }

    private void NewSubjectExisChrtPck_Unfocused(object sender, FocusEventArgs e)
    {
        NewSubjectExisChrtPck.IsVisible = false;
        NewSubjectExisChrtPck.Unfocus();
    }
}

NewSubjectViewModel.cs(为简洁起见被截断)

class NewSubjectViewModel : BaseViewModel
{
    private ObservableCollection<Chart> charts;

    public ObservableCollection<Chart> Charts
    {
        get { return charts; }
        private set
        {
            charts = value;
            OnPropertyChanged();
        }
    }

    public Command LoadChartsCommand { get; set; }

    public NewSubjectViewModel()
    {
        LoadChartsCommand = 
            new Command(
                async () => await ExecuteLoadChartsCommand()
            );
    }

    private async Task ExecuteLoadChartsCommand()
    {
        try
        {
            IndicatorRunning = true;

            var list = await App.Database.GetChartsAsync();
            Charts = new ObservableCollection<Chart>(list);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
    }
}

感谢您的帮助!如果您需要查看其他内容,请告诉我。

首先,直到第二次单击按钮时,我才能够重现模态不显示的问题。您可能需要为此提供更多代码。为了使用您的代码示例,我不得不用其他东西替换 var list = await App.Database.GetChartsAsync(); 来模拟 returns 一个空列表的长 运行 任务。还必须用 Name 属性 创建一个 Chart 类型。更不用说BaseViewModel了。将来,请提供所有代码以重现该问题,以便尝试帮助您的人员完成最少的工作。 Stack Overflow 上有一个称为 MCVE 的概念(最小、完整、可验证的示例):http://whosebug.com/help/mcve

就是说,也许第一次点击实际上是聚焦模拟器并使其成为活动应用程序,然后第二次是按钮上的第一次实际点击?这个我可以重现。 IOW,如果模拟器不是前台应用程序,您必须单击它一次以使其处于活动状态,然后您的应用程序将处理点击。

至于不受欢迎的 UI,您是否意识到选择器 UI 基本上是一个可点击的标签,点击后会显示实际的选择器模式?因此,当您使其可见时,您正在使其可见的是标签 UI,它具有线条和标题(如果已设置),并且当您聚焦该标签时,将显示实际的选择器对话框。如果您根本不想看到 UI 标签,那为什么要让它可见呢?您可以在不使其可见的情况下聚焦它,因此只需删除行 NewSubjectExisChrtPck.IsVisible = true;

作为旁注,当您调用 _viewModel.LoadChartsCommand.Execute(null); 调用异步方法 var list = await App.Database.GetChartsAsync(); 时,因此 LoadChartsCommand returns 在您设置图表 属性,然后调用 _viewModel.LoadChartsCommand.Execute(null); 之后的代码也在 LoadChartsCommand 真正完成之前执行,因此您使选择器可见并在 LoadChartsCommand 完成之前将其聚焦,所以如果您正在加载实际项目供选择器显示,它们可能不会第一次出现。也许这只是示例代码,但我认为没有理由在这里使用命令,而您应该只调用一个可等待的任务。您没有绑定到 LoadChartsCommand,所以我认为您没有理由在这种情况下甚至使用 Command。相反,我建议制作 ExecuteLoadChartsCommand public 并直接调用它,例如:

private async void NewSubjectExisChrtBtn_Clicked(object sender, EventArgs e)
{
    //_viewModel.LoadChartsCommand.Execute(null); // Returns immediately, so picker not loaded with items yet.
    await _viewModel.ExecuteLoadChartsCommand(); // Waits for method to finish before before presenting the picker.
    //NewSubjectExisChrtPck.IsVisible = true;
    NewSubjectExisChrtPck.Focus();
}