I'm trying to bind ObservableCollection of ValueTuples to ComboBox in WPF using Caliburn.Micro framework MVVM. When I do that in ViewModel:
private ObservableCollection<Tuple<string, string>> databasesFromDisk;
public ObservableCollection<Tuple<string, string>> DatabasesFromDisk
{
get => databasesFromDisk;
set
{
databasesFromDisk = value;
NotifyOfPropertyChange(() => DatabasesFromDisk);
}
}
and in XAML View:
<ComboBox x:Name="DatabasesFromDisk" DisplayMemberPath="Item1"/>
it works, ComboBox fills with first strings. But when I try to use C# 7 and change to:
private ObservableCollection<(string name, string path)> databasesFromDisk;
public ObservableCollection<(string name, string path)> DatabasesFromDisk
{
get => databasesFromDisk;
set
{
databasesFromDisk = value;
NotifyOfPropertyChange(() => DatabasesFromDisk);
}
}
it doesn't work when I don't change XAML - it shows empty list. It doesn't work when I change to DisplayMemberPath="name"
- the same empty list. And it doesn't work properly when I remove DisplayMemberPath
- it shows whole list but with both strings concatenated.
How can I do it with ValueTuples?
Before C# 7 all the Items of Tuple are properties which are bindable. In C# 7 ValueTuple are fields which are not bindable.
https://msdn.microsoft.com/en-us/library/dd386940(v=vs.110).aspx https://github.com/dotnet/corefx/blob/master/src/System.ValueTuple/src/System/ValueTuple/ValueTuple.cs#L291
One of the possible solution can be using the IValueConverter
public class ValueTupleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var tuple = value as (string name, string path)?;
if (tuple == null)
return null;
return tuple.Value.Name;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
<ComboBox x:Name="DatabasesFromDisk">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource ValueTupleConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>