Hallo zusammen,
Ich hoffe ich bin im richtigen Forumsbereich mit meiner Frage gelandet.
Ich bin derzeit dabei eine Anwendung zu schreiben, bei welcher unter anderem mittels Picker ein "Parent" Item ausgewählt werden kann. Genau dieser Picker ärgert mich etwas.
Die Page hat als BindingContext als ViewModel, über diesen werden verschiedene Informationen unter anderem für den Picker bereitgestellt werden.
Was funktioniert:
ItemsSource zuweisen -> Mir wird mein Dropdown wie erwartet dargestellt
ItemDisplayBinding -> Name wird richtig dargestellt
Was nur teilweise funktioniert:
SelectedItem -> Das verändern des Wertes im Dropdown und anschließende speichern funktioniert wunderbar und wird korrekt in meine Datenbank im Hintergrund geschrieben. Wenn ich jedoch den Eintrag wieder "aufrufe" ist die Auswahl im Dropdown leer.
Ich hoffe ihr versteht soweit mein Problem und könnt mir der hoffentlichen Kleinigkeit helfen 🙂
relevante Page.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
......
<ContentPage.BindingContext>
<dataViewModels:CategoryViewModel/>
</ContentPage.BindingContext>
<Grid Margin="5">
......
<Label Text="{x:Static s:strings.categoryNameLabel}"
Grid.Column="0"
Grid.Row="0"/>
<Entry Text="{Binding Name}"
Grid.Row="0"
Grid.Column="1"/>
<Label Text="{x:Static s:strings.categoryParentLabel}"
Grid.Column="0"
Grid.Row="1"/>
<Picker x:Name="ParentPicker"
Grid.Row="1"
Grid.Column="1"
ItemsSource="{Binding ParentCategories,Mode=TwoWay}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding Parent,Mode=TwoWay}"
WidthRequest="200"/>
<Button Text="{x:Static s:strings.saveButton}"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
Command="{Binding SaveCategoryCommand}"/>
</Grid>
</ContentPage>
relevante Page.xaml.cs
using HouseholdSuiteCross.DataViewModel;
namespace HouseHoldSuiteCross.Views
{
[QueryProperty(nameof(CategoryId),nameof(CategoryId))]
public partial class CategoryPage : ContentPage
{
public int CategoryId
{
set
{
LoadCategoryAsync(value);
}
}
public CategoryPage()
{
InitializeComponent();
}
public async void LoadCategoryAsync(int catId)
{
(BindingContext as CategoryViewModel).Model = await CategoryService.GetCategoryWithIdAsync(catId);
}
protected override async void OnAppearing()
{
base.OnAppearing();
await (BindingContext as CategoryViewModel).UpdateParentCategories();
}
}
}
mein ViewModel:
namespace HouseholdSuiteCross.DataViewModel
{
public class CategoryViewModel : BaseViewModel
{
private ObservableCollection<CategoryModel> _ParentCategories = new();
private CategoryModel _model = new();
//Public Properties
public CategoryModel Model
{
get { return _model; }
set
{
if(value != _model)
{
_model = value;
OnPropertyChanged(nameof(Model));
OnPropertyChanged(nameof(Name));
OnPropertyChanged((nameof(Parent)));
OnPropertyChanged((nameof(NameParentCategory)));
OnPropertyChanged((nameof(CanSave)));
}
}
}
public string Name
{
get { return Model.Name; }
set
{
if(Model.Name != value)
{
Model.Name = value;
OnPropertyChanged(nameof(Name));
OnPropertyChanged((nameof(CanSave)));
}
}
}
public int Id
{
get { return Model.Id; }
}
public CategoryModel Parent
{
get
{
return Model.Parent;
}
set
{
if(Model.Parent != value)
{
Model.Parent = value;
OnPropertyChanged((nameof(Parent)));
OnPropertyChanged((nameof(NameParentCategory)));
}
}
}
public ObservableCollection<CategoryModel> ParentCategories
{
get => _ParentCategories;
set
{
if (ParentCategories != value)
{
_ParentCategories = value;
OnPropertyChanged(nameof(ParentCategories));
}
}
}
public override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
(SaveCategoryCommand as Command).ChangeCanExecute();
}
//Methods
public async Task UpdateParentCategories()
{
List<CategoryModel>allCat = await CategoryService.GetAllCategoriesAsync();
ParentCategories.Clear();
foreach(CategoryModel category in allCat)
{
ParentCategories.Add(category);
}
}
}
}
Bitte die richtigen Code Tags nutzen.
Hallo Toube
Das sieht eigentlich ganz gut aus. Hast du eine Lösung gefunden?
Wenn nicht, vielleicht probierst du mal bei dem Picker sowas:
SelectedItem="{Binding Parent, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Gruß
Alf
Hallo Alf,
danke für deinen Hinweis.
Bei Maui scheint es kein
UpdateSourceTrigger
mehr zu geben.
Mode=TwoWay
habe ich ergänzt, leider hat es nicht zum Erfolg geführt.
Was ich noch ganz spannend finde:
Ich habe einen Versuch gestartet die Auswahl mittels Code zuzuweisen
public async void LoadCategoryAsync(int catId)
{
(BindingContext as CategoryViewModel).Model = await CategoryService.GetCategoryWithIdAsync(catId);
ParentPicker.SelectedItem = (BindingContext as CategoryViewModel).Parent;
}
Das Feld bleibt beim Laden eines Items mit Parent immer noch leer.
Folgende Veränderung führt zum Erfolg, zumindest mittels Code behind.
protected override async void OnAppearing()
{
base.OnAppearing();
var bindingContext = (BindingContext as CategoryViewModel);
await bindingContext.UpdateParentCategories();
if (bindingContext.Parent == null)
{
return;
}
foreach (var cat in bindingContext.ParentCategories)
{
if (cat.Id == bindingContext.Parent.Id)
{
ParentPicker.SelectedItem = cat;
}
}
}
Falls mir jemand noch erklären könnte weshalb es nicht im xaml klappt wäre super 🙂
Entgültige Lösung des Problems gefunden:
Ich hatte das SelectedItem auf dem public CategoryModel Parent gebunden gehabt.
Wenn ich in meinen ViewModel den Datentyp von CategoryModel auf den Datentyp CategoryViewModel umändere funktioniert es.
Problem ist gelöst 🙂
Problem ist gelöst 🙂
👍
Das mit dem UpdateSourceTrigger ist ja interessant. Hatte ja seine Berechtigung.
Mode=TwoWay ist imho der Default-Wert.