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();
}
在这一点上拔头发。如果启用,我的选择器在 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();
}