Reputation: 221
Having some problems with my MVVM Application. So the scenario is the following:
In my MainWindow.xaml, I have a ContentControl placed in a Grid Column, its content is bind to the CurrentViewModel which will be rendered to the appropriate View (in this case, Overview.xaml).
<ContentControl Grid.Row="1" Grid.Column="1" Content="{Binding CurrentViewModel}">
Within this particular view (Overview.xaml) there are multiple UserControls placed within a StackPanel.
<ScrollViewer CanContentScroll="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<StackPanel CanVerticallyScroll="True" CanHorizontallyScroll="True">
<views:DiagramView DataContext="{Binding Path=DiagramViewModel, Source={StaticResource Locator}}" />
<views:IncomeCollectionView DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
<views:ExpenseCollectionView DataContext="{Binding Path=ExpensesViewModel, Source={StaticResource Locator}}" />
<views:CheckCollectionView DataContext="{Binding Path=ChecksViewModel, Source={StaticResource Locator}}" />
<views:BalanceCollectionView DataContext="{Binding Path=BalancesViewModel, Source={StaticResource Locator}}" />
<views:VacationCollectionView DataContext="{Binding Path=VacationsViewModel, Source={StaticResource Locator}}" />
<views:KHCollectionView DataContext="{Binding Path=KhViewModel, Source={StaticResource Locator}}" />
<views:OctaviaCollectionView DataContext="{Binding Path=OctaviaViewModel, Source={StaticResource Locator}}" />
</StackPanel>
</ScrollViewer>
Each UserControl within this StackPanel has a very similar look (obviously there are more stuff in the XAML). There is no constant value regarding Width or Height within my application.
<ListView ItemsSource="{Binding Source={StaticResource groupedCollection}}" SelectedItem="{Binding CurrentItem}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Items[0].CurrentCategory}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="12" Rows="1" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding GeneratedColumn}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding EncryptedAmount}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Got paid on " />
<TextBlock Text="{Binding Date}" />
</StackPanel>
<Button Content="details"
Command="{Binding Path=DataContext.ShowDialogCommand,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
CommandParameter="QuickEdit"/>
<Button Content="remove" Command="{Binding RemoveCommand}" CommandParameter="Income removed." />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The problem is that I can't seem to make the vertical scrollviewer work. It is displayed because I make it visible, but it's disabled. Obviously the StackPanel is gonna grow indefintely, but isn't there a way for it to calculate how much space is needed? Because most of the content is just cut off right now. So I tried to put scrollviewer in every possible place, but they're all disabled.
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<ScrollViewer>
<ContentPresenter Cursor="{TemplateBinding Cursor}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So then I tried dropping the StackPanel implementation and tried it with a Grid. Nope, it doesn't work either. Obviously I'm missing some basis solution here, but just can't figure it out. Any ideas would be appreciated, seems like a very common scenario to be honest. Cheers
<ScrollViewer CanContentScroll="True"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<views:DiagramView DataContext="{Binding Path=DiagramViewModel, Source={StaticResource Locator}}" />
<views:IncomeCollectionView Grid.Row="1" DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
<views:ExpenseCollectionView Grid.Row="2" DataContext="{Binding Path=ExpensesViewModel, Source={StaticResource Locator}}" />
<views:CheckCollectionView Grid.Row="3" DataContext="{Binding Path=ChecksViewModel, Source={StaticResource Locator}}" />
...etc...
</Grid>
</ScrollViewer>
Edit: The DiagramView UserControl contains the following:
<UserControl x:Class="Expense.Manager.WPF.Views.DiagramView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:pie="clr-namespace:Expense.Manager.WPF.CustomPie"
xmlns:local="clr-namespace:Expense.Manager.WPF.Shared"
mc:Ignorable="d">
<UserControl.Resources>
<local:BoolToBrushConverter x:Key="BoolToBrushConverter" />
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Income this month: " />
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="Retrieving data...">
<Binding Path="EncryptedCurrentMonthIncome" Mode="TwoWay" IsAsync="True" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<pie:PieChart Data="{Binding PieChartIncomeData, Mode=TwoWay}" Width="250" PieWidth="130" PieHeight="130" Height="140" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Expenses this month: " />
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="Retrieving data...">
<Binding Path="CurrentMonthExpense" Mode="TwoWay" IsAsync="True" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<pie:PieChart Data="{Binding PieChartExpenseData, Mode=TwoWay}" Width="250" PieWidth="130" PieHeight="130" Height="140" />
</StackPanel>
<StackPanel Grid.Column="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding VacationsLeft}" />
<TextBlock Text=" days left" />
</StackPanel>
<ItemsControl ItemsSource="{Binding VacationsPerYearCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Margin="5, 0, 0, 0" Height="25" Width="4" Fill="{Binding Converter={StaticResource BoolToBrushConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Bank savings:" />
<TextBlock Text="{Binding BankSavings}" />
</StackPanel>
</StackPanel>
</Grid>
IncomeCollectionView:
<UserControl x:Class="Expense.Manager.WPF.Views.IncomeCollectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:views="clr-namespace:Expense.Manager.WPF.Views"
mc:Ignorable="d">
<UserControl.Resources>
<CollectionViewSource x:Key="groupedCollection" IsLiveGroupingRequested="True" Source="{Binding Collection}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="CurrentCategory" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayName}" Foreground="White" FontWeight="SemiBold" Padding="5" Background="SteelBlue" />
<ListView Grid.Row="1" ItemsSource="{Binding Source={StaticResource groupedCollection}}" SelectedItem="{Binding CurrentItem}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Items[0].CurrentCategory}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Columns="12" Rows="1" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding GeneratedColumn}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding EncryptedAmount}" />
<TextBlock Grid.Row="1" Text="{Binding Date}" />
<Button Grid.Row="2" Content="details"
Command="{Binding Path=DataContext.ShowDialogCommand,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
CommandParameter="QuickEdit"/>
<Button Grid.Row="3" Content="remove" Command="{Binding RemoveCommand}" CommandParameter="Income removed." />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
and where it is used: why is the listview not resizing itself after resizing the window itself?
<ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<views:IncomeCollectionView Grid.Row="1" DataContext="{Binding Path=IncomesViewModel, Source={StaticResource Locator}}" />
</Grid>
</ScrollViewer>
Upvotes: 0
Views: 547
Reputation: 69979
I tried dropping the StackPanel
implementation and tried it with a Grid
. Nope, it doesn't work either.
That's almost correct, apart from the last sentence. Using a Grid
is half of the answer, because the StackPanel
has no functionality to resize its items... you just need to inform the ScrollViewer
when to scroll. Take this example:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Rectangle Fill="Cyan" />
<Rectangle Grid.Row="1" Fill="Green" />
<Rectangle Grid.Row="2" Fill="Red" />
<Rectangle Grid.Row="3" Fill="Blue" />
<Rectangle Grid.Row="4" Fill="Orange" />
<Rectangle Grid.Row="5" Fill="Purple" />
<Rectangle Grid.Row="6" Fill="Yellow" />
</Grid>
</ScrollViewer>
This XAML will make the ScrollViewer ScrollBar
appear (once the Window.Height
is small enough), but if you remove the RowDefinition.Height
values (thereby giving each row a proportion of the whole Grid.Height
), you'll see your previous situation where no ScrollBar
appears.
Now, none of us want to hard code constant values into our UIs, but you can do this using the Auto
setting on the RowDefinition.Height
properties instead. Unlike these Rectangle
s, your controls will all have some Height
, so your solution is to set each of your Grid.RowDefinition
s like this:
<RowDefinition Height="Auto" />
This will provide your controls with as much space as they need within the Grid
and therefore (hopefully) they will have more Height
together than the ScrollViewer
and therefore the ScrollViewer
will display its vertical ScrollBar
.
Upvotes: 0