【问题标题】:x:Bind StackOverflow when trying to x:Bind ListView.SelectedItem using TwoWay modex:尝试使用 TwoWay 模式绑定 ListView.SelectedItem 时的 x:绑定 StackOverflow
【发布时间】:2016-02-15 20:47:51
【问题描述】:

我正在尝试使用新的 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 使用旧的良好绑定,它只是简单地工作。这并不奇怪。

Surprise 使用了导致 StackOverflowException 的新 x:Bind。在 OneWay 模式下工作正常 - 但 TwoWay 每当我单击其中一个项目时都会引发 StackOverflowException... 搞笑...

我的问题很简单——“为什么以及如何解决这个问题?”

【问题讨论】:

  • 我无法确认该报告,因为我目前手边没有 VS2015 的副本。但是,您的异常应该包括一个堆栈跟踪,大概包括编译器生成的代码以支持{x:Bind} 表达式,并且至少应该解释导致异常的递归的来源。一旦找到递归的来源,您应该能够确定导致递归的代码是否由 XAML 编译器合理生成;如果没有,请考虑在connect.microsoft.com 上提交错误报告

标签: c# windows-10 win-universal-app xbind


【解决方案1】:

我遇到了同样的问题。 查看堆栈跟踪,我发现我的列表视图正在修改视图模型,它正在提升 OnPropertyChanged,它修改了列表视图...... 要解决这个问题,您应该修改绑定属性的设置器:

public string BestItem
{
  get { return _bestItem; }
  set
  {
    if (_bestItem != value)
    {
      _bestItem = value;
      OnPropertyChanged(nameof(BestItem));
    }
  }
}

【讨论】:

    【解决方案2】:

    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>
    

    【讨论】:

      猜你喜欢
      • 2011-08-10
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      相关资源
      最近更新 更多