На самом деле я не вижу , почему вы используете SelectedItem
и SelectedIndex
, но я думаю, что то, чего вы пытаетесь достичь, может быть достигнуто легче.
все, я не думаю, что вам нужно ObservableCollection
типов в вашем примере, так как вы все равно устанавливаете направления и не изменяете коллекцию. Более того, насколько я могу судить, возиться с индексами совершенно не нужно. В любом случае вы используете строки, и хотя String
не является типом значения, но является ссылочным типом, вы практически не можете различить guish два String
экземпляра, которые имеют одинаковое содержимое, следовательно, присваивая соответствующие значения SelectedDirection
и SelectedFrame
достаточно.
Следующие проверки кажутся мне излишними
if (Directions.Contains(value))
if (EnumUtils.ToEnumFromString<FrameType>(SelectedFrame) == FrameType.Road &&
!DirectionsRoad.Contains(value))
, поскольку Directions
в любом случае установлено на DirectionsRoad
, если SelectedFrame
установлено на "Road"
. Следовательно, я бы предположил, что второе условие не оценивается как true
в любом случае. Следовательно, SelectedDirection
можно упростить:
public string SelectedDirection
{
get => _selectedDirection;
set
{
if (_selectedDirection != value && Directions.Contains(value))
{
_selectedDirection = value;
OnPropertyChanged();
}
}
}
В установщике SelectedFrame
происходит много вещей, которые я бы рефакторировал для методов самостоятельно, чтобы улучшить ясность.
public string SelectedFrame
{
get => _selectedFrame;
set
{
if (_selectedFrame != value)
{
_selectedFrame = value;
UpdateAvailableDirections();
OnPropertyChanged();
}
}
}
private void UpdateAvailableDirections()
{
// store the selected direction
var previouslySelectedDirection = SelectedDirection;
Directions = GetValidDirectionsByFrameType(EnumUtils.ToEnumFromString<FrameType>(SelectedFrame));
SelectedDirection = GetSelectedDirection(previoslySelectedDirection, Directions);
}
private string[] GetValidDirectionsByFrameType(FrameType frameType)
{
return frameType == FrameType.Road ? DirectionsRoad : DirectionsAll;
}
private string GetSelectedDirection(string previouslySelectedDirection, string[] validDirections)
{
return validDirections.Contains(previouslySelectedDirection) ? previouslySelectedDirection : DefaultDirection;
}
При установке SelectedItem
вместо работы с индексами должны отображаться правильные значения.
Что касается вашего вопроса, может ли эта логика c лучше подходить в обработчике событий или в установщике, зависит от ваших требований. Если вам нужен только индекс, событие SelectedIndexChanged
может сработать для вас, но если значение требуется в нескольких местах и методах, которые не вызываются обработчиком события, представленное решение может быть более жизнеспособным.
Edit
Вы были правы, это не имеет никакого отношения к использованию SelectedIndex
и SelectedItem
. Вопрос немного более тонкий.
Я построил быстрое подтверждение концепции и нашел следующее:
- Предполагая, что
SelectedDirection
равно "Right"
(и индекс установлен соответственно) - Когда установлено
Directions
, SelectedItem
на сборщике сбрасывается SelectedDirection
установлено на null
this.Directions.Contains(value)
оценивается на false
, следовательно _selectedDirection
не установлено (это верно для SelectedDirectionIndex
, поскольку значение -1
фильтруется с помощью if(!value < 0 || value >= this.Directions.Count))
- Когда впоследствии устанавливается
SelectedDirection
, значение по-прежнему равно "Right"
, следовательно, OnPropertyChanged
не вызывается (так как значения одинаковы), а SelectedItem
не установлено
Таким образом, существует несоответствие между значением, фактически сохраненным Picker
, и свойством в модель представления, которая приводит к неожиданному поведению.
Как смягчить проблему?
Я бы все равно придерживался кода без индексов (если они вам действительно не нужны) и использовал бы строковые значения .
Есть и другие возможности, но я бы изменил установщик на SelectedDirection
. Когда вы позволили установить значение * 10 80 *, PropertyChanged
будет повышаться должным образом, если впоследствии будет установлено значение Right
. Если вам действительно нужно отфильтровать, какое значение установлено, вы все равно должны увеличить OnPropertyChanged
, чтобы сообщить Picker
, что значение изменилось (предотвращая несоответствие между фактическим значением Picker
s и моделью представления)
public string SelectedDirection
{
get => _selectedDirection;
set
{
if (_selectedDirection != value)
{
if(Directions.Contains(value))
{
_selectedDirection = value;
}
else
{
_selectedDirection = DirectionTypes.Right.ToString();
}
OnPropertyChanged();
}
}
}