C
C#7mo ago
DapperDeer

Dependency Properties and When to use ObservableCollections

Hello, I'm trying to figure out how best to architect my little Pokedex application that I'm making and would appreciate some guidance/assistance. In my MainWindow code-behind, it's getting a service that pulls all the Pokemon information from an API that I'm calling and storing it in an ObservableCollection, which the PokemonDetails is binding to. In the PokemonDetails code-behind, I have a Dependency Property but something about this binding is not working. I don't think I'm doing the Dependency Property correctly, and I'm not sure if using an ObservableCollection in my MainWindow.xaml.cs is necessary. My thought process was that the collection will be updated, notify the PropertyChanged event (which I don't actually subscribe it to anything, maybe that's the issue?), which would notify the PokemonDetails UserControl, update its dep property, and display the list correctly. Code is in replies to this thread.
1 Reply
DapperDeer
DapperDeer7mo ago
MainWindow.xaml:
<ContentControl Grid.Column="1">
<local:PokemonDetails Pokemon="{Binding Pokemon, UpdateSourceTrigger=PropertyChanged, BindsDirectlyToSource=True}"/>
</ContentControl>
<ContentControl Grid.Column="1">
<local:PokemonDetails Pokemon="{Binding Pokemon, UpdateSourceTrigger=PropertyChanged, BindsDirectlyToSource=True}"/>
</ContentControl>
PokemonDetails.xaml (truncated for brevity):
<ListBox
x:Name="PokemonListBox"
Grid.Row="1"
HorizontalContentAlignment="Center"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Pokemon}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding ImageSource}" Width="64" Height="64" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox
x:Name="PokemonListBox"
Grid.Row="1"
HorizontalContentAlignment="Center"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Pokemon}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding ImageSource}" Width="64" Height="64" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
PokemonDetails.xaml.cs (truncated for brevity)
public ObservableCollection<Pokemon> Pokemon
{
get => (ObservableCollection<Pokemon>)GetValue(PokemonContentsProperty);
set
{
SetValue(PokemonContentsProperty, value);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Pokemon)));
}
}

public static readonly DependencyProperty PokemonContentsProperty = DependencyProperty.Register(
name: "Pokemon",
propertyType: typeof(ObservableCollection<Pokemon>),
ownerType: typeof(PokemonDetails));
public ObservableCollection<Pokemon> Pokemon
{
get => (ObservableCollection<Pokemon>)GetValue(PokemonContentsProperty);
set
{
SetValue(PokemonContentsProperty, value);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Pokemon)));
}
}

public static readonly DependencyProperty PokemonContentsProperty = DependencyProperty.Register(
name: "Pokemon",
propertyType: typeof(ObservableCollection<Pokemon>),
ownerType: typeof(PokemonDetails));
The ListBox in PokemonDetails.xaml is within a Grid, which is specifying <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type wpfApp1:PokemonDetails}}}"> I fgured out how to get this to work: I needed to create a PropertyChangedCallback and set the PokemonDetails collection to the new value. I would've thought this just happened with the Setter, but I guess not?