На форме есть TabControl, элементы которого берутся из ViewModel, на каждой вкладке TabControl расположен ScrollViewer внутри которого несколько страниц Page. Я хочу иметь возможность произвольно распологать страницы на вкладке, описывая их расположение во ViewModel. Ширина и высота страниц фиксированная. Я сделал реализацию, которая позволяет решать эту задачу, если нужно расположить страницы в несоклько колонок, или несоклько рядов, с несколькими страницами в колонке или в ряду. Но возникла необходимость сделать такой макет как на картике, и нужно разбить левую колонку еще на две колонки, а в будущем может придется еще более мелкое разбиение. Кто-нибудь знает решение получше?
<TabControl Height="{Binding ElementName=helperTabControlHeight, Path=ActualHeight}" ItemsSource="{Binding TabControlItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer Height="auto" Width="auto" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<StackPanel>
<!-- Ряды со страницами -->
<ItemsControl ItemsSource="{Binding HorizontalStackPanels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding PageItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Frame Content="{Binding Page}" NavigationUIVisibility="Hidden"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- /Ряды со страницами -->
<!-- Колонки со страницами -->
<ItemsControl ItemsSource="{Binding VerticalStackPanels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding PageItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Frame Content="{Binding Page}" NavigationUIVisibility="Hidden"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- /Колонки со страницами -->
</StackPanel>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
private void CreateTabControlItems()
{
TabControlItem tabControlItem = new TabControlItem { Header = "Вкладка 1", HorizontalStackPanels = new List<MyStackPanel>(), VerticalStackPanels = new List<MyStackPanel>() };
tabControlItem.VerticalStackPanels.Add(new MyStackPanel { PageItems = new List<PageItem>() { new PageItem { Page = new Views.Pages.Page1() } } });
tabControlItem.VerticalStackPanels.Add(new MyStackPanel { PageItems = new List<PageItem>() { new PageItem { Page = new Views.Pages.Page2() }, new PageItem { Page = new Views.Pages.Page3() } } });
TabControlItems.Add(tabControlItem);
}
public class TabControlItem
{
public string Header { get; set; } //заголовок вкладки
public List<MyStackPanel> HorizontalStackPanels { get; set; } //ряды со страницами
public List<MyStackPanel> VerticalStackPanels { get; set; } //колонки со страницами. Предполагается использовать либо HorizontalStackPanels либо VerticalStackPanels, в зависимости от того как лучше скомпоновать страницы
}
public class MyStackPanel
{
public List<PageItem> PageItems { get; set; } //страницы, расположенные в один ряд или в одну колонку
}
public class PageItem
{
public Page Page { get; set; }
}

Ширина и высота страниц фиксированная- а это плохой знак. Хардкода в верстке не должно быть. – aepot Jun 13 '22 at 14:04