0

So I'm creating "cards" to visually represent a collection of objects within a StackPanel (which I'm using a list to hold these objects):

MainWindow XAML:

<Window /* ... */> <StackPanel x:Name="Deck" Orientation="Horizontal" /> </Window> 

MainWindow C#:

public partial class MainWindow : Window { /* ... */ private void OnDataReceived(List<Reading> readings) { foreach(Reading r in readings) { Deck.Children.Add(new Card { Id = r.Id, Value = r.Value }); } } } 

UserControl XAML:

<UserControl /* ... */ x:Name="crd"> <Label Content="{Binding Path=Id, ElementName=crd}" /> <Label Content="{Binding Path=Value, ElementName=crd} /> </UserControl> 

UserControl C#:

public partial class LoggerRepresentation : UserControl { public string Id { get; set; } public int Value { get; set; } /* ... */ } 

Upon adding one element to Deck.Children, its' visual representation does appear in the StackPanel as expected. However, DP seems to lack something as the Labels binding Id and Value remain empty.

(The idea to give x:Name="crd" to my UserControl and then use it within the Binding as ElementName has been plugged from the answer to a seemingly related question, but may be misleading in this case.)

1
  • 3
    It looks like you're doing things like its used to be in windows programming. you should check MVVM and INotifyPropertyChanged interface. Commented Sep 7, 2018 at 11:13

1 Answer 1

0

You should use an ItemsControl whenever you want to display a dynamic collection of items.

Replace the StackPanel in your XAML markup with an ItemsControl:

<ItemsControl ItemsSource="{Binding Cards}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <local:LoggerRepresentation /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

Bind directly to the source properties of the corresponding Card object in the UserControl (and replace the Label elements with TextBlocks):

<TextBlock Text="{Binding Path=Id}" /> <TextBlock Text="{Binding Path=Value} /> 

Create a view model class that exposes a collection of Card objects through a public property and move your application logic over to this one:

public class ViewModel { public ObservableCollection<Card> Cards { get; } = new ObservableCollection<Card>(); //... private void OnDataReceived(List<Reading> readings) { foreach (Reading r in readings) { Cards.Add(new Card { Id = r.Id, Value = r.Value }); } } } 

Set the DataContext of the view where the ItemsControl is defined to an instance of the view model class:

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new ViewModel(); } } 

This design pattern is known as Model-View-ViewModel (MVVM) and it's the recommended pattern to use when developing XAML based UI applications. You will find a lot more to read and learn about it if your Google.

Sign up to request clarification or add additional context in comments.

7 Comments

<local:LoggerRepresentation /> isn't allowed inside <ItemsControl.ItemTemplate>, but is accepted when I wrap the Template tag in <DataTemplate>. Is that correct?
I still seem to get it wrong, at least I'm getting errors to the output now: System.Windows.Data Error: 40 : BindingExpression path error: 'Value' property not found on 'object' ''ViewModel' (HashCode=20770076)'. BindingExpression:Path=Value; DataItem='ViewModel' (HashCode=20770076); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') Is the "Cards" in <ItemsControl ItemsSource="{Binding Cards}"> referencing the "Cards" in public ObservableCollection<Card> Cards { get; } = new ObservableCollection<Card>();? That's beyond me still
It should, unless you override the DataContext somewhere.
How would I ideally add items to the list from the MainWindow now? I've added a function "Add()" to the ViewModel class and am simply routing received items into the Cards property. Is that correct?
You should use commands. But that's another story. Please ask a new question if you have another issue.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.