I am trying to create a Custom User Control with a ListView in it that contains a Data Template looking like this:
<ComboBox ItemsSource="{Binding ItemsSource, ElementName=root}"
SelectedItem="{Binding SelectedItem, ElementName=root, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- This is what I tried:
Working but not what I want <TextBox Text="{Binding Name}"/>
Returns the List only the word "FallBack" <TextBox Text="{Binding ItemText, ElementName=root}" />
Returns the LIst empty <TextBox Text="{Binding ItemText}" />
-->
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the code behind I have created the necessary dependency properties for this case (so I assume) the only relevant one is regarding the Item Text and it looks like that:
#region ItemText
public string ItemText
{
get { return (string)GetValue(ItemTextProperty); }
set { SetValue(ItemTextProperty, value); }
}
// Using a DependencyProperty as the backing store for ItemText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemTextProperty =
DependencyProperty.Register("ItemText", typeof(string), typeof(CardComboBox), new PropertyMetadata("FallBack"));
#endregion
What I would like to do is to add the User Control like that
<local:CardComboBox ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}" ItemText="{Binding Name}" IsEnabled="True" />
Option one:
<TextBox Text="{Binding Name}"/>
works fine because the PropertyName of the Class Person is Name, but I obviously do not want to HardCode it. I want to bind it to whichever property I like.
Option 2:
<TextBox Text="{Binding ItemText, ElementName=root}" />
Gives me the list of 7 items (as per list) but just displays the word "Fallback" because of the DependencyPropertyMetadata.
Option 3:
<TextBox Text="{Binding ItemText}" />
Gives me the list but with no text at all.
I also tried to work with relativeSource but only with similar results.
#region Person
Person _selectedPerson;
public Person SelectedPerson
{
get => _selectedPerson;
set
{
if (value != _selectedPerson)
{
_selectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
}
ObservableCollection<Person> _persons;
public ObservableCollection<Person> Persons
{
get => _persons;
set
{
if (value != _persons)
{
_persons = value;
OnPropertyChanged("Persons");
}
}
}
public void populatePersons()
{
Persons = new ObservableCollection<Person>();
Persons.Add(new Person("Carl"));
Persons.Add(new Person("Max"));
Persons.Add(new Person("May"));
Persons.Add(new Person("Jen"));
Persons.Add(new Person("Charly"));
Persons.Add(new Person("Nora"));
Persons.Add(new Person("Yvonne"));
}
#endregion
I have added the List I am binding to. The Method Populate Persons is called in the constructor of the ViewModel.
The closest solution working so far is to expose the ItemContentTemplate Dependency Property and then to bind it to a static resource (e.g. from App.xaml)
The XAML of the UserControl looks like this:
<StackPanel Style="{StaticResource CardStackPanel}" Orientation="{Binding Orientation, ElementName=root}" >
<Label x:Name="Label" Content="{Binding TitleText, ElementName=root}"/>
<ComboBox ItemsSource ="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=UserControl}}"
ItemTemplate="{Binding ItemContentTemplate, RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}" />
</StackPanel>
the Code Behind for the ComboBox Part:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CardComboBox));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(CardComboBox));
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public DataTemplate ItemContentTemplate
{
get { return (DataTemplate)GetValue(ItemContentTemplateProperty); }
set { SetValue(ItemContentTemplateProperty, value); }
}
public static readonly DependencyProperty ItemContentTemplateProperty =
DependencyProperty.Register("ItemContentTemplate", typeof(DataTemplate), typeof(CardComboBox));
The Static Ressource in App.xaml (example):
<DataTemplate x:Key="FirstNamesTemplate">
<Label Content="{Binding FirstName}"/>
</DataTemplate>
The Implementation of a ComboBoxCard looks now like this:
<local:CardComboBox ItemsSource="{Binding PersonModels}" SelectedItem="{Binding SelectedPersonModel, Mode=TwoWay}" ItemContentTemplate="{StaticResource FirstNamesTemplate}" TitleText="With StaticResource" IsEnabled="False"/>
This pattern allows to implement ComboBoxes or ListViews in Custom UserControls .