我有一个输入字段和一些选择器,该选择器是一个自定义选择器。 当我在输入字段中输入一些文本然后单击选择器时,它将触发两次,因此,当我单击一个项目时,选择器弹出窗口将保留,直到我单击“取消”或再次选择一个项目。如果我使用默认选择器,则事件会像正常情况一样触发,因此我怀疑它与viewmodel绑定无关。 您可能会注意到我有两个选择器,它仅在第一个选择器中发生。
关于我做错了什么,我可以指出正确的方向吗?
<StackLayout >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
<RowDefinition Height="40"/>
<RowDefinition Height="35"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Entry Text="" FontSize="16" Grid.Row="0" Grid.Column="0"
Grid.ColumnSpan="2"/>
<Label Text="Bedrooms:" Grid.Row="1" Grid.Column="0"
Grid.ColumnSpan="1" Style="{StaticResource entryLableStyle}"/>
<autocomplete:RoundPicker x:Name="bedPicker" Grid.Row="2"
Grid.Column="0" Grid.ColumnSpan="1" ItemsSource="{Binding BedsList}"
SelectedItem="{Binding BedSelected}" ItemDisplayBinding="{Binding Name}"
Style="{StaticResource pickerStyle}" />
<Label Text="Min Price:" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1" Style="{StaticResource entryLableStyle}"/>
<autocomplete:RoundPicker Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="1" ItemsSource="{Binding MaxPriceList}" SelectedItem="{Binding MaxPriceSelected}" ItemDisplayBinding="{Binding maxPrice}" Style="{StaticResource pickerStyle}"/>
</Grid>
</StackLayout>
ViewModel:
public class TestViewModel : BaseViewModel
{
public string BedsAmount { get; set; }
public string MaxPrice { get; set; }
public List<MaxPriceModel> MaxPriceList { get; set; }
public List<Beds> BedsList { get; set; }
private Beds _bedType;
public Beds BedSelected
{
get
{
return _bedType;
}
set
{
if (_bedType != value)
{
_bedType = value;
if (_bedType != null)
{
BedsAmount = _bedType.Name;
}
}
}
}
private MaxPriceModel _maxPriceSelected;
public MaxPriceModel MaxPriceSelected
{
get
{
return _maxPriceSelected;
}
set
{
if (_maxPriceSelected != value)
{
_maxPriceSelected = value;
if (_maxPriceSelected != null)
{
MaxPrice = _maxPriceSelected.maxPrice;
}
}
}
}
public class Beds
{
public string Name { get; set; }
}
public TestViewModel()
{
BedsList = GetBeds();
MaxPriceList = GetMaxPrice();
}
public List<MaxPriceModel> GetMaxPrice()
{
var maxprice = new List<MaxPriceModel>()
{
new MaxPriceModel(){maxPrice = "100 000"},
new MaxPriceModel(){maxPrice = "200 000"},
new MaxPriceModel(){maxPrice = "300 000"},
new MaxPriceModel(){maxPrice = "400 000"},
new MaxPriceModel(){maxPrice = "500 000"},
new MaxPriceModel(){maxPrice = "600 000"},
new MaxPriceModel(){maxPrice = "700 000"},
new MaxPriceModel(){maxPrice = "800 000"},
new MaxPriceModel(){maxPrice = "900 000"},
new MaxPriceModel(){maxPrice = "1 000 000"},
};
return maxprice;
}
public List<Beds> GetBeds()
{
var beds = new List<Beds>()
{
new Beds() { Name = "1" },
new Beds() { Name = "2" },
new Beds() { Name = "3" },
new Beds() { Name = "4" },
new Beds() { Name = "5" },
new Beds() { Name = "6" },
new Beds() { Name = "7" },
new Beds() { Name = "8" },
new Beds() { Name = "9" },
new Beds() { Name = "10" },
};
return beds;
}
}
App.Android中的自定义渲染器
[assembly: ExportRenderer(typeof(RoundPicker),
typeof(RounndedPickerRenderAndroid))]
namespace PropertyApp.Droid.Models
class RounndedPickerRenderAndroid : PickerRenderer
{
private AlertDialog _dialog;
IElementController ElementController => Element as IElementController;
public RounndedPickerRenderAndroid(Context context) : base(context)
{
}
protected override void
OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
var gradientDrawable = new GradientDrawable();
gradientDrawable.SetCornerRadius(0f);
gradientDrawable.SetStroke(2,
Android.Graphics.Color.LightGray);
gradientDrawable.SetColor(Android.Graphics.Color.White);
Control.SetBackground(gradientDrawable);
Control.SetHintTextColor(Android.Graphics.Color.Gray);
Control.SetPadding(20, 0, 0, 0);
Control.SetSingleLine(true);
Control.Click += Control_Click;
}
}
内容页面:
namespace App.Views{[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PickerTest : ContentPage
{
private TestViewModel vm;
public PickerTest ()
{
InitializeComponent ();
vm = new TestViewModel();
BindingContext = vm;
}
}
}
namespace App.Droid
{
[Activity(Label = "App", Icon = "@mipmap/icon", Theme = "@style/MainTheme",
MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize |
ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
FFImageLoading.Forms.Platform.CachedImageRenderer
.Init(enableFastRenderer: true);
base.OnCreate(savedInstanceState);
Rg.Plugins.Popup.Popup.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App(MultiMediaPickerService.SharedInstance));
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
}
public override void OnRequestPermissionsResult(int requestCode, string[]
permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode,
permissions, grantResults);
PermissionsImplementation.Current.
OnRequestPermissionsResult(requestCode,
permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions,
grantResults);
}
protected override void OnActivityResult(int requestCode, Result
resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
MultiMediaPickerService.SharedInstance.OnActivityResult(requestCode,
resultCode, data);
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (data != null))
{
// Set the filename as the completion of the Task
PickImageTaskCompletionSource.SetResult(data.DataString);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
public static MainActivity Current { private set; get; }
public static readonly int PickImageId = 1000;
public TaskCompletionSource<string> PickImageTaskCompletionSource { set;
get; }
}
}
自定义渲染:
using Android.Content;
using Android.Graphics.Drawables;
using App.Droid.Models;
using App.Helpers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(RoundPicker),
typeof(RounndedPickerRenderAndroid))]
namespace App.Droid.Models
{
class RounndedPickerRenderAndroid : PickerRenderer
{
public RounndedPickerRenderAndroid(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker>
e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
var gradientDrawable = new GradientDrawable();
gradientDrawable.SetCornerRadius(0f);
gradientDrawable.SetStroke(2,
Android.Graphics.Color.LightGray);
gradientDrawable.SetColor(Android.Graphics.Color.White);
Control.SetBackground(gradientDrawable);
Control.SetHintTextColor(Android.Graphics.Color.Gray);
Control.SetPadding(20, 0, 0, 0);
Control.SetSingleLine(true);
Control.Click += Control_Click;
}
}
protected override void Dispose(bool disposing)
{
Control.Click -= Control_Click;
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Picker model = Element;
var picker = new NumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
// set style here
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetBackgroundColor(Android.Graphics.Color.White);
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.Value = model.SelectedIndex;
picker.SetScrollIndicators(3);
picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
picker.Visibility = ViewStates.Visible;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetNegativeButton("Cancel ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Ok ", (s, a) =>
{
ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
}
}
}