2016-02-15 1 views
4

Я пытаюсь связать ListView.SelectedItem с помощью нового x: Bind. Мой код:x: Bind StackOverflow при попытке x: Bind ListView.SelectedItem с использованием режима TwoWay

Вид:

//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> 

Code-за:

//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 из второй строки использует старый хороший привязку, который просто работает. Не удивительно.

Сюрприз поставляется с тем, который использует новый x: Bind, вызывающий StackOverflowException. Хорошо работает с режимом OneWay - но TwoWay бросает StackOverflowException всякий раз, когда я нажимаю один из элементов ... веселый ...

Мой вопрос очень прост - «Почему и как это решить?»

+0

Я не могу подтвердить отчет, так как у меня нет копии VS2015 в данный момент. Тем не менее, ваше исключение должно включать в себя трассировку стека, предположительно такую, которая включает в себя код, сгенерированный компилятором, для поддержки выражений '{x: Bind} и который должен по крайней мере объяснить, откуда берется рекурсия, вызывающая исключение. Как только вы обнаружите источник рекурсии, вы должны убедиться, что код, вызывающий рекурсию, был разумно сгенерирован компилятором XAML или нет; если нет, рассмотрите вопрос об отправке отчета об ошибке на https://connect.microsoft.com/ –

ответ

3

Я столкнулся с той же проблемой. Рассматривая трассировку стека, я выяснил, что мой список изменил режим просмотра, который поднимал OnPropertyChanged, который меняет список ... Чтобы решить эту проблему, вы должны изменить установщик связанного свойства:

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

SelectedItem вашего ListView от типа 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; 
    } 
} 

Теперь вы просто должны ссылаться на этот конвертер в вашем х: 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> 

Смежные вопросы