Zasadniczo najlepszą drogą, aby to zrobić w WPF jest... tego nie robić.
WPF opiera się o tzw. wiązanie danych (data binding), co w skrócie oznacza, że XAML jest w stanie zrobić takie rzeczy jak wygenerowanie potrzebnych ci rzeczy za ciebie - nie powinieneś się przejmować tworzeniem kontrolek, wystarczy, że dostarczysz do widoku dane. Możesz zrobić tak:
Stworzyć sobie klasę odpowiadającą twojemu obrazkowi:
Kopiuj
class Thumbnail
{
public string Path;
}
Stwórz sobie teraz kolekcję takich obrazków, na przykład List<Thumbnail>, a potem musisz ją przypisać jako ItemsSource jakiegoś czegoś, co ładnie ci je poukłada w liście - na przykład ListBox. myListBox.ItemsSource = GetListOfThumbnails();
To spowoduje już teraz, że dostajesz listę, w której masz dla każdego obrazka wynik jego ToString(). Wygląda to słabo, ale ListBox może mieć coś, co się nazywa ItemTemplate, co mówi mu, w jaki sposób ma wyświetlać swoje dzieci. Da się to skleić z UniformGrid w taki też sposób, że dostaniesz widok w kolumnach:
Kopiuj
<ListBox ScrollViewer.VerticalScrollBarVisibility="Disabled" x:Name="thumbnails">
<ListBox.ItemTemplate>
<DataTemplate>
<Button>
<Image Source="{Binding Path}" Width="300" Height="300" Stretch="Uniform" />
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
I masz coś takiego:

Alternatywnie, WrapPanel zamiast UniformGrid, aby nie była stała liczba kolumn, ale żeby się dostosowywał do zawartości:

Każdy z elementów ListBox jest przyciskiem o określonych wymiarach, który w środku ma obrazek pobierany z odpowiedniego pliku.