我尝试使用新的x:Bind绑定ListView.SelectedItem。我的代码:
查看:
//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" };
}
}
}
如您所见,我的MainPage上有两个ListView控件。如果您尝试运行此代码,请根据您要检查的绑定类型对其中一个进行评论。 第二行的ListView使用旧的好Binding,它只是简单的工作。这里不足为奇。
使用新的x:Bind导致StackOverflowException。使用OneWay模式可以正常工作 - 但只要我点击其中一个项目,TwoWay就会抛出StackOverflowException ...搞笑......
我的问题很简单 - &#34;为什么以及如何解决这个问题?&#34;
答案 0 :(得分:4)
我遇到了同样的问题。 看一下堆栈跟踪,我发现我的listview正在修改viewmodel,这正在上升OnPropertyChanged,它修改了listview ... 要解决这个问题,您应该修改绑定属性的setter:
public string BestItem
{
get { return _bestItem; }
set
{
if (_bestItem != value)
{
_bestItem = value;
OnPropertyChanged(nameof(BestItem));
}
}
}
答案 1 :(得分:3)
ListView的SelectedItem
来自Object
类型,但您尝试将其称为String
,因此您需要的是一个简单的转换器。
我发现除了实施IValueConverter
之外,您可以使用通用的方法而不做任何事情 - 这在answer
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>