尝试在列表视图 MVVM Xamarin 中设置选择器 [英] Trying to set picker within listview MVVM Xamarin
问题描述
尝试通过使用 SelectedItem 将初始值设置为选择器.如果选择器不在列表视图中,我可以毫无问题地执行此操作.但是,一旦我尝试在列表视图中完成此操作,就没有骰子.
我永远无法让选择器显示最初下载的值.如果我对条目使用相同的绑定,它会显示预期的字符串.
想法??
这可以在这个简单的独立项目中重现.请帮忙.谢谢.
clRecipeIngredients
公共类 clRecipeIngredient{公共 int RecipeIngredientsID { 获取;放;}公共 int RecipeIDLookedUP { 获取;放;}公共 int IngredientIDLookedUp { 获取;放;}公共双数量{得到;放;}公共 int UnitIDLookedUp { 获取;放;}public bool HiddenFlag { 获取;放;}公共字符串 UnitName { get;放;}公共字符串成分名称 { 获取;放;}公共字符串注释 { 获取;放;}
我检查了你的示例,你可以像下面这样修改它.
在 Xaml 中
在视图模型中
ObservableCollection 在默认情况下实现了接口 INotifyPropertyChanged.因此,您可以简化 ViewModel 中的代码.
注意:您不能将 SelectItem 的值直接设置为字符串,即使它们相等.你需要像下面这样设置
ing.IngredientName = listIngredients[0];
所以 ViewModel 可能会喜欢
公共类 testPageViewModel : BaseViewModel{公共 ObservableCollection下载的食谱成分{得到;设置;}公共 ObservableCollection;列表成分{获取;放;}//私有clRecipeDataBase recipeDataBase;公共 testPageViewModel(){//recipeDataBase = new clRecipeDataBase();btnPress = new Command(madeIt);DownloadRecipeIngredients = new ObservableCollection();listIngredients = new ObservableCollection();获取数据();}异步 void getData(){//选择器成分数据//clIngredient[] arrayIngredients = await recipeDataBase.getIngredientData();//clIngredient[] arrayIngredients = new clIngredient[5];//arrayIngredients[0].IngredientName = "Apple";//arrayIngredients[1].IngredientName = "Salt";//arrayIngredients[2].IngredientName = "Buter";//arrayIngredients[3].IngredientName = "面粉";//arrayIngredients[4].IngredientName = "Egg";listIngredients.Add(苹果");listIngredients.Add(盐");listIngredients.Add(黄油");listIngredients.Add(面粉");listIngredients.Add(鸡蛋");//for (int i = 0; i < arrayIngredients.Length; i++)//{//_listIngredients.Add(arrayIngredients[i].IngredientName);//}//clRecipeIngredient[] arryRecipeIngredients = await recipeDataBase.getRecipeIngredientsDataByRecipeID(310);//硬编码到脆皮比萨食谱clRecipeIngredient ing = new clRecipeIngredient();ing.IngredientName = listIngredients[0];ing.Quantity = 1;ing.UnitName = "杯子";ing.Comments = "Comments0";clRecipeIngredient ing2 = new clRecipeIngredient();ing2.IngredientName = listIngredients[1];ing2.Quantity = 2;ing2.UnitName =整体";ing2.Comments = "Comments1";下载了RecipeIngredients.Add(ing);下载的食谱成分.添加(ing2);}公共 ICommand btnPress { 获取;私人订制;}void madeIt(clRecipeIngredient x){Console.WriteLine(x.IngredientName + " -- " + x.Comments);//_downloadedRecipeIngredients.Remove(x);}}
并且不要忘记在您的模型中实现 INotifyPropertyChanged,因为 IngredientName 的值将被更改.
公共类 clRecipeIngredient : INotifyPropertyChanged{公共事件 PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));}//...字符串成分名称;公共字符串成分名称{得到{返回成分名称;}放{如果(成分名称!= 值){成分名称 = 值;OnPropertyChanged(成分名称");}}}//...}
Trying to set the initial value to a picker through the use of SelectedItem. I can do this without any issue if the picker isn't within a listview. However, once I try to accomplish this in a listview no dice.
I never can get the picker to display the initially downloaded value. If I use the same binding for an entry it displays the expected string.
Thoughts??
This can be reproduced in this simplistic standalone project. Please help. Thanks.
https://github.com/smarcus3/DebuggingProject
XAML
<ListView x:Name="listView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemsSource="{Binding downloadedRecipeIngredients}"> <!--SelectedItem="{Binding SelectedItem}"-->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<!-- Element Label -->
<Entry VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" Text="{Binding IngredientName}"/>
<!--<Picker x:Name="pickerIngredient" HorizontalOptions = "StartAndExpand" ItemsSource="{Binding listIngredients}" BindingContext="{Binding Source={x:Reference Page}, Path=BindingContext}" SelectedItem="{Binding IngredientName}" WidthRequest="100"/>-->
<Picker x:Name="pickerIngredientancestor" HorizontalOptions = "StartAndExpand" WidthRequest="100" ItemsSource="{Binding listIngredients, Source={RelativeSource AncestorType={x:Type viewModel:testPageViewModel}}}" SelectedItem="{Binding IngredientName}"/>
<Entry Text="{Binding Quantity}" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" />
<Entry Text="{Binding UnitName}" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" />
<Entry Text="{Binding Comments}" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" />
<!-- Assessment Menu Icon -->
<Label Text="Clickable Label" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.btnPress, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
VIEW MODEL
public class testPageViewModel : BaseViewModel
{
clRecipeIngredient[] _downloadedRecipeIngredients;
public clRecipeIngredient[] downloadedRecipeIngredients
{
get {
return _downloadedRecipeIngredients;
}
set
{
//if (downloadedRecipeIngredients != value)
//{
_downloadedRecipeIngredients = value;
OnPropertyChanged("downloadedRecipeIngredients");
//}
}
}
//Lists for Pickers
ObservableCollection<string> _listIngredients = new ObservableCollection<string>();
public ObservableCollection<string> listIngredients { get { return _listIngredients; } }
private clRecipeDataBase recipeDataBase;
public testPageViewModel()
{
recipeDataBase = new clRecipeDataBase();
btnPress = new Command<clRecipeIngredient>(madeIt);
getData();
}
async void getData()
{
//PICKER INGREDIENT DATA
clIngredient[] tmp = await recipeDataBase.getIngredientData();
for (int i = 0; i < tmp.Length; i++)
{
_listIngredients.Add(tmp[i].IngredientName);
}
_downloadedRecipeIngredients = await recipeDataBase.getRecipeIngredientsDataByRecipeID(310); //HARDCODED TO CRISPY PIZZA RECIPE
OnPropertyChanged("downloadedRecipeIngredients");
}
public ICommand btnPress { get; private set; }
void madeIt(clRecipeIngredient x)
{
Console.WriteLine(x.IngredientName + " -- " + x.Comments);
//_downloadedRecipeIngredients.Remove(x);
}
}
clRecipeIngredients
public class clRecipeIngredient
{
public int RecipeIngredientsID { get; set; }
public int RecipeIDLookedUP { get; set; }
public int IngredientIDLookedUp { get; set; }
public double Quantity { get; set; }
public int UnitIDLookedUp { get; set; }
public bool HiddenFlag { get; set; }
public string UnitName { get; set; }
public string IngredientName { get; set; }
public string Comments { get; set; }
I checked your sample and you could modify it like following .
in Xaml
<Picker HorizontalOptions = "StartAndExpand" WidthRequest="100" ItemsSource="{Binding Path=BindingContext.listIngredients, Source={x:Reference Page}}" SelectedItem="{Binding IngredientName, Mode=TwoWay}" />
in ViewModel
ObservableCollection had implemented the interface INotifyPropertyChanged in default . So you could simplify the code in your ViewModel .
Note : You could not set the value of SelectItem as a string directly even if they are equal . You need to set it like following
ing.IngredientName = listIngredients[0];
So the ViewModel could like
public class testPageViewModel : BaseViewModel
{
public ObservableCollection<clRecipeIngredient> downloadedRecipeIngredients
{
get;set;
}
public ObservableCollection<string> listIngredients { get; set; }
//private clRecipeDataBase recipeDataBase;
public testPageViewModel()
{
//recipeDataBase = new clRecipeDataBase();
btnPress = new Command<clRecipeIngredient>(madeIt);
downloadedRecipeIngredients = new ObservableCollection<clRecipeIngredient>();
listIngredients = new ObservableCollection<string>();
getData();
}
async void getData()
{
//PICKER INGREDIENT DATA
//clIngredient[] arrayIngredients = await recipeDataBase.getIngredientData();
//clIngredient[] arrayIngredients = new clIngredient[5];
//arrayIngredients[0].IngredientName = "Apple";
//arrayIngredients[1].IngredientName = "Salt";
//arrayIngredients[2].IngredientName = "Buuter";
//arrayIngredients[3].IngredientName = "Flour";
//arrayIngredients[4].IngredientName = "Egg";
listIngredients.Add("Apple");
listIngredients.Add("Salt");
listIngredients.Add("Butter");
listIngredients.Add("Flour");
listIngredients.Add("Egg");
//for (int i = 0; i < arrayIngredients.Length; i++)
//{
// _listIngredients.Add(arrayIngredients[i].IngredientName);
//}
//clRecipeIngredient[] arryRecipeIngredients = await recipeDataBase.getRecipeIngredientsDataByRecipeID(310); //HARDCODED TO CRISPY PIZZA RECIPE
clRecipeIngredient ing = new clRecipeIngredient();
ing.IngredientName = listIngredients[0];
ing.Quantity = 1;
ing.UnitName = "Cups";
ing.Comments = "Comments0";
clRecipeIngredient ing2 = new clRecipeIngredient();
ing2.IngredientName = listIngredients[1];
ing2.Quantity = 2;
ing2.UnitName = "Whole";
ing2.Comments = "Comments1";
downloadedRecipeIngredients.Add(ing);
downloadedRecipeIngredients.Add(ing2);
}
public ICommand btnPress { get; private set; }
void madeIt(clRecipeIngredient x)
{
Console.WriteLine(x.IngredientName + " -- " + x.Comments);
//_downloadedRecipeIngredients.Remove(x);
}
}
And don't forget to implement INotifyPropertyChanged in your model as the value of IngredientName will been changed .
public class clRecipeIngredient : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(
[CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
//...
string ingredientName;
public string IngredientName
{
get
{
return ingredientName;
}
set
{
if (ingredientName != value)
{
ingredientName = value;
OnPropertyChanged("IngredientName");
}
}
}
//...
}
这篇关于尝试在列表视图 MVVM Xamarin 中设置选择器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!