У меня есть средство выбора внутри CollectionView, которое должно выбрать предопределенный элемент ColorNav
, но при его запуске элемент не выбирается.
КСАМЛ:
<StackLayout>
<Label Text = "Players" />
<CollectionView ItemsSource = "{Binding PlayerList}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType = "model:Player">
<SwipeView>
<Border>
<Grid ColumnDefinitions = "*, *, *" ColumnSpacing = "1" >
<Label Grid.Column = "0" Text = "{Binding Name}" />
<Picker Grid.Column = "1" ItemsSource = "{Binding ColorsPicker, Source = {RelativeSource AncestorType = {x:Type viewmodel:MainViewModel}}}" ItemDisplayBinding = "{Binding Name}" SelectedItem = "{Binding ColorNav}"/>
<Label Grid.Column = "2" Text = "{Binding ColorNav.Name}"/>
</Grid>
</Border>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text = "Save" Command = "{Binding SaveCommand}"/>
</StackLayout>
С#
public class Player
{
public string Name { get; set; } = default!;
public int ColorId { get; set; } = default!;
public Colour ColorNav { get; set; } = default!;
}
public class Colour
{
public int ColorId { get; set; }
public string Name { get; set; } = default!;
}
public MainViewModel() {
ColorsPicker = [
new Colour {
ColorId = 1,
Name = "Red"
},
new Colour {
ColorId = 2,
Name = "Blue"
},
new Colour {
ColorId = 3,
Name = "Yellow"
},
];
PlayerList = [
new Player {
Name = "John",
ColorId = 1,
ColorNav = ColorsPicker[0],
},
new Player {
Name = "Carla",
ColorId = 3,
ColorNav = ColorsPicker[2],
},
];
}
Во время отладки я вижу, что ColorNav загружается в BindingContext, но каким-то образом он становится нулевым при запуске страницы. Когда я нажимаю «Сохранить», ColorNav
для каждого игрока имеет значение null. Если я удалю SelectedItem = "{Binding ColorNav}"
из средства выбора, ColorNav останется таким, как ожидалось.У каждого игрока в BindingContext инициализирован ColorNav
Я инициализирую ColorNav
для каждого игрока в модели представления, прежде чем привязывать его к средству выбора. Я добавил некоторый контекст к вопросу.
Вы реализовали OnPropertyChanged
в своей виртуальной машине и использовали наблюдаемые коллекции? Другая проблема может заключаться в том, что список ItemSource
средства выбора отличается от списка SelectedItem
, вызывающего проблему, проверьте это: stackoverflow.com/search?q=%5Bmaui%5Dpicker+collection
ItemsSource привязан к ObservableCollection<Colour> colorsPicker
, и ColorNav
тоже является Colour
. Как я уже упоминал, SelectedItem ColorNav
меняется на ноль при загрузке страницы. Я считаю, что это происходит потому, что он пытается загрузить SelectedItem перед загрузкой ItemsSource и, не найдя ничего, устанавливает для него значение null.
Вы можете поместить переменную ColorsPicker
и переменную ColorNav
внутри модели Player.cs
и реализовать интерфейс INotifyPropertyChanged
для модели Player.cs
.
public class Player: INotifyPropertyChanged
{
public string Name { get; set; } = default!;
public int ColorId { get; set; } = default!;
// public Colour ColorNav { get; set; } = default!;
public ObservableCollection<Colour> ColorsPicker { get; set; } = new ObservableCollection<Colour>();
//add a property for the SelectedItem property of picker
private Colour _colorNav;
public Colour ColorNav
{
set
{
SetProperty(ref _colorNav, value);
}
get { return _colorNav; }
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Кроме того, если мы хотим обновить пользовательский интерфейс (<Label Grid.Column = "2" Text = "{Binding ColorNav.Name}"
) при изменении выбранного элемента текущего средства выбора, нам также необходимо реализовать интерфейс INotifyPropertyChanged
для модели Colour.cs
public class Colour: INotifyPropertyChanged
{
public int ColorId { get; set; }
//public string Name { get; set; } = default!;
private string _name;
public string Name
{
set
{
SetProperty(ref _name, value);
}
get { return _name; }
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Затем мы можем инициализировать MainViewModel.cs
следующим образом:
public class MainViewModel
{
public ObservableCollection<Colour> ColorsPicker { get; set; } = new ObservableCollection<Colour>();
public ObservableCollection<Player> PlayerList { get; set; } = new ObservableCollection<Player>();
public MainViewModel() {
ColorsPicker = [
new Colour {
ColorId = 1,
Name = "Red"
},
new Colour {
ColorId = 2,
Name = "Blue"
},
new Colour {
ColorId = 3,
Name = "Yellow"
},
];
PlayerList = [
new Player {
Name = "John",
ColorId = 1,
ColorNav = ColorsPicker[0],
ColorsPicker = ColorsPicker // initialize ColorsPicker
},
new Player {
Name = "Carla",
ColorId = 3,
ColorNav = ColorsPicker[2],
ColorsPicker = ColorsPicker // initialize ColorsPicker
},
];
}
}
И затем мы можем связать данные следующим образом:
<CollectionView ItemsSource = "{Binding PlayerList}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType = "model:Player">
<SwipeView>
<Border>
<Grid ColumnDefinitions = "*, *, *" ColumnSpacing = "1" >
<Label Grid.Column = "0" Text = "{Binding Name}" />
<!--<Picker Grid.Column = "1" ItemsSource = "{Binding ColorsPicker, Source = {RelativeSource AncestorType = {x:Type viewmodel:MainViewModel}}}" ItemDisplayBinding = "{Binding Name}" SelectedItem = "{Binding ColorNav}"/>-->
<Picker Grid.Column = "1" ItemsSource = "{Binding ColorsPicker}" ItemDisplayBinding = "{Binding Name}" SelectedItem = "{Binding ColorNav ,Mode=TwoWay}"/>
<Label Grid.Column = "2" Text = "{Binding ColorNav.Name}"/>
</Grid>
</Border>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Спасибо, Джесси. Добавление ColorsPicker к каждому экземпляру Player решает проблему, хотя инициализация одной и той же коллекции для каждого экземпляра кажется странной, что может быть неэффективно (я думаю), но это работает :)
Вы имеете в виду
ColorNav
инициализацию после привязки?