x:Bind Stackru при попытке x:Bind ListView.SelectedItem с использованием режима TwoWay
Я пытаюсь связать ListView.SelectedItem с помощью нового x:Bind. Мой код:
Посмотреть:
//MainPage.xaml:
<Page
x:Class="BrokenListSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BrokenListSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="Beige">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ListView Grid.Row="0" Background="LawnGreen"
ItemsSource="{x:Bind ViewModel.MyItems, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.BestItem, Mode=TwoWay}"
Width="300" Height="300"/>
<ListView Grid.Row="1" Background="LawnGreen"
ItemsSource="{Binding MyItems, Mode=OneWay}"
SelectedItem="{Binding BestItem, Mode=TwoWay}"
Width="300" Height="300"/>
</Grid>
Код-за:
//MainPage.xaml.cs:
using Windows.UI.Xaml.Controls;
namespace BrokenListSample
{
public sealed partial class MainPage : Page
{
public MainPageViewModel ViewModel { get; set; }
public MainPage()
{
InitializeComponent();
DataContextChanged += (s, e) => { ViewModel = DataContext as MainPageViewModel; };
DataContext = new MainPageViewModel();
}
}
}
и наконец ViewModel:
//MainPageViewModel.cs:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace BrokenListSample
{
public class MainPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private ObservableCollection<string> _myItems;
public ObservableCollection<string> MyItems
{
get { return _myItems; }
set { _myItems = value; OnPropertyChanged("MyItems"); }
}
private string _bestItem;
public string BestItem
{
get { return _bestItem; }
set { _bestItem = value; OnPropertyChanged("BestItem"); }
}
public MainPageViewModel()
{
MyItems = new ObservableCollection<string>() { "One", "Two", "Three", "Four" };
}
}
}
Как видите, у меня есть два элемента управления ListView на главной странице. Если вы пытаетесь запустить этот код, прокомментируйте один из них в зависимости от того, какую привязку вы хотите проверить. ListView из второй строки использует старый добрый Binding, который просто работает. Здесь нет ничего удивительного.
Сюрприз поставляется с тем, который использует новый x: Bind, который вызывает StackruException. Работает нормально с режимом OneWay - но TwoWay выдает исключение StackruException, когда я нажимаю на один из элементов... веселый...
Мой вопрос очень прост - "Почему и как это решить?"
2 ответа
Я столкнулся с той же проблемой. Глядя на трассировку стека, я обнаружил, что мой просмотр списка изменял модель представления, которая поднимала OnPropertyChanged, который изменяет представление списка... Чтобы решить это, вы должны изменить установщик свойства bound:
public string BestItem
{
get { return _bestItem; }
set
{
if (_bestItem != value)
{
_bestItem = value;
OnPropertyChanged(nameof(BestItem));
}
}
}
SelectedItem
вашего ListView от типа Object
но вы пытаетесь назвать это String
так что вам нужен простой конвертер.
Я обнаружил, что вы можете просто использовать общий, не делая ничего, кроме реализации IValueConverter
- это было упомянуто в этом ответе
public class GenericConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// no convert to a specific type needed -> the "value" is already an instance of the correct type.
return value;
}
}
Теперь вам просто нужно сослаться на этот конвертер в вашем x:Bind
<ListView ...
ItemsSource="{x:Bind ViewModel.MyItems, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.BestItem, Mode=TwoWay,
Converter={StaticResource GenericConverter}}"
.../>
А в вашем App.xaml (чтобы этот конвертер был доступен для всех ваших просмотров):
<Application
x:Class="Namespace.App"
...
xmlns:Converters="using:Namespace.Converters">
<Application.Resources>
<ResourceDictionary>
...
<Converters:GenericConverter x:Key="GenericConverter"/>
...
</ResourceDictionary>
</Application.Resources>