I'm trying to bind ListView.SelectedItem using new x:Bind. My code:
View:
//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-behind:
//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();
}
}
}
and finally 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" };
}
}
}
As you see I have two ListView controls on my MainPage. If you are trying to run this code, please comment one of them depending of what kind of binding you want to check. ListView from second row uses old good Binding, that just simply works. No surprise here.
Surprise comes with the one that uses new x:Bind which is causing StackOverflowException. Works fine with OneWay mode - but TwoWay throws StackOverflowException whenever I click one of the items... hilarious...
My question is very simple - "Why and how to solve that?"
I was facing the same issue. Looking at the stack trace, I've figured out that my listview was modifying the viewmodel, that was rising the OnPropertyChanged, that modifies the listview... To solve that, you should modify the setter of the bound property:
public string BestItem
{
get { return _bestItem; }
set
{
if (_bestItem != value)
{
_bestItem = value;
OnPropertyChanged(nameof(BestItem));
}
}
}
The SelectedItem
of your ListView is from type Object
but you try to refer to it as String
so what you need is a simple converter.
I have found that you can just use a generic one without doing anything but implementing IValueConverter
- that was mentioned in this 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;
}
}
Now you just have to reference this converter in your x:Bind
<ListView ...
ItemsSource="{x:Bind ViewModel.MyItems, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.BestItem, Mode=TwoWay,
Converter={StaticResource GenericConverter}}"
.../>
And in your App.xaml (to make this converter available to all your views):
<Application
x:Class="Namespace.App"
...
xmlns:Converters="using:Namespace.Converters">
<Application.Resources>
<ResourceDictionary>
...
<Converters:GenericConverter x:Key="GenericConverter"/>
...
</ResourceDictionary>
</Application.Resources>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With