Nowość w WPF - Jaka jest kontrola / rozpoczęcie pracy?

Jestem nfob WPF i walczę z wyborem odpowiedniej kontroli, aby uzyskać pożądany układ.

Próbuję narysować na ekranie pęczek kwadratów (wirtualne notatki post-it). Każda nuta będzie miała przyzwoity rozmiar (około 150 pikseli lub więcej) i mogą być setki takich notatek. Chcę, żeby cała rzecz była przewijana, abyś mógł zmienić rozmiar okna, jak chcesz, a całość powinna być powiększalna.

Zrobiłem to i to działa.
Ale to, co zrobiłem, wydaje się strasznie złe ....

W kodzie dynamicznie tworzę notatki i dodaje je do olbrzymiego płótna. Robię ręcznie matematykę, aby określić, gdzie umieścić każdą notatkę i jak duże powinno być płótno. Dodałem kilka etykiet na górze i musiałem wrócić i dodać wartość „Przesunięcie Y”, aby przesunąć wszystkie kwadraty w dół. W rzeczywistości generuję trzy różne kontrolki płótna, a następnie dodaję każdy z nich do panelu stosu, który znajduje się wewnątrz ScrollViewera. Dodałem pasek przewijania i ustawiłem panel stosu, aby powiększać i pomniejszać widok podczas regulacji paska.

To „działa”, ale czuję, że naprawdę nie używam WPF w taki sposób, w jaki ma być używany. Próbowałem osiągnąć to samo za pomocą siatki, ale nie wyglądało na to, że siatka sama się odpowiednio dopasowuje.

Czy ktoś może mi powiedzieć „lepszy” sposób na osiągnięcie tego samego wyglądu?

Oto mój kod Xaml - jak widać; nie ma wiele do zrobienia ....

<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="25" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Slider x:Name="ZoomSlider" Minimum="0.01" Value="1" Maximum="2" Margin="0,0,0,6" />
    <ScrollViewer x:Name="MyScroller" Grid.Row="1" HorizontalScrollBarVisibility="Visible"  HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
        <StackPanel x:Name="TicketsGrid"  Background="White" HorizontalAlignment="Center">

        </StackPanel>
    </ScrollViewer>
</Grid>            

A oto co robię w kodzie (brzydkie !!!)

For Each myWorkItem As WorkItem In myWorkItems
        Dim newRect As New Border

        newRect.Width = TicketSizeX
        newRect.Height = TicketSizeY

        If myWorkItem.State.ToUpper.Contains("HOLD") Then
            newRect.Background = New SolidColorBrush(Colors.Purple)
        Else
            newRect.Background = New SolidColorBrush(Color)
        End If

        newRect.CornerRadius = New System.Windows.CornerRadius(5)
        newRect.BorderThickness = New System.Windows.Thickness(1)
        newRect.BorderBrush = New SolidColorBrush(Colors.Black)

        Dim myPanel As New StackPanel
        newRect.Child = myPanel

        Dim lblTitle As New Label
        lblTitle.Content = myWorkItem.Id
        lblTitle.FontWeight = System.Windows.FontWeights.Bold

        Dim lblDesc As New TextBlock
        lblDesc.Text = myWorkItem.Title
        lblDesc.TextWrapping = TextWrapping.Wrap


        myPanel.Children.Add(lblTitle)
        myPanel.Children.Add(lblDesc)

        newRect.SetValue(Canvas.LeftProperty, CType(((TicketCount Mod TicketsXPerUser) * TicketStepX) + (xOffset * TicketStepX * TicketsXPerUser), Double))
        newRect.SetValue(Canvas.TopProperty, CType(((Math.Floor((TicketCount / TicketsXPerUser)) * TicketStepY)) + NameLabelHeight, Double))

        myCanvas.Children.Add(newRect)
        TicketCount += 1
    Next

    MyCanvas.Width = (TicketStepX * TicketsXPerUser) * myTFS.SharedCodeTeam.Count
    MyCanvas.Height = (CType(((Math.Floor((MaxTicket / TicketsXPerUser)) + 1) * TicketStepY), Double))

    TicketsGrid.Children.Add(MyCanvas)

questionAnswers(1)

yourAnswerToTheQuestion