C
C#11mo ago
Fluffy

Scrollviewer not staying at the bottom when new insert. MVVM .NET Frameworks 4.5 XAML

I have the following xaml. This works fine, HOWEVER, whenever a new message is inserted into the ItemsControl my scrollviewer doesn't update and stays in plays. This means that new messages can't be seen unless your scroll down manually and I cannot for the life of me figure out why it won't stay in its relative position.
<ItemsControl.ItemTemplate>

<DataTemplate>

<Border x:Name="MessageBorder" MinHeight="40" MinWidth="280" BorderThickness="1"
Background="#EFEBE9" BorderBrush="#BCAAA4"
Margin="10,0,60,10" CornerRadius="4" SnapsToDevicePixels="True" HorizontalAlignment="Left">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>

<TextBlock x:Name="MessageTxtBlock" Grid.Row="1" Margin="7,5,7,0" TextWrapping="Wrap"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Text="{Binding Message}"/>

<TextBlock Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Stretch"
Margin="0,0,5,0" FontSize="10" Opacity="0.8"
Text="{Binding Time, StringFormat={}{0:t}}"/>
</Grid>
</Border>

<DataTemplate.Triggers>
omitted for brevity
</DataTemplate.Triggers>

</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer x:Name="MessageScroller" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>

<DataTemplate>

<Border x:Name="MessageBorder" MinHeight="40" MinWidth="280" BorderThickness="1"
Background="#EFEBE9" BorderBrush="#BCAAA4"
Margin="10,0,60,10" CornerRadius="4" SnapsToDevicePixels="True" HorizontalAlignment="Left">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>

<TextBlock x:Name="MessageTxtBlock" Grid.Row="1" Margin="7,5,7,0" TextWrapping="Wrap"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Text="{Binding Message}"/>

<TextBlock Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Stretch"
Margin="0,0,5,0" FontSize="10" Opacity="0.8"
Text="{Binding Time, StringFormat={}{0:t}}"/>
</Grid>
</Border>

<DataTemplate.Triggers>
omitted for brevity
</DataTemplate.Triggers>

</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer x:Name="MessageScroller" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
3 Replies
Buddy
Buddy11mo ago
You need to code it so that it does.
MODiX
MODiX11mo ago
Rules of WPF:

❌ Avoid the WPF Designer to eliminate a category of confusing bugs
❌ Don't rely on Margin as the primary tool for layouts
❌ Avoid writing UserControls or subclassing to extend a default control -- use Behaviors instead (Microsoft.Xaml.Behaviors.Wpf)

✅ Write XAML by hand and autoformat with "Ctrl K,D" or XAML Styler
✅ Rely upon XAML Hot Reload to design your app's UI at runtime
✅ Use layout controls (Grid, DockPanel, etc) to support proper resizing
✅ Use data binding to eliminate glue code and state synchronization issues
✅ Use collection controls and DataTemplate to dynamically create lists of controls
✅ Learn MVVM to create maintainable apps
✅ Use the Dispatcher to update controls from non-UI threads
✅ WPF's default controls can be easily modernized via $wpfuilibs
✅ Include relevant XAML, code-behind, and ViewModel code for questions when possible
Rules of WPF:

❌ Avoid the WPF Designer to eliminate a category of confusing bugs
❌ Don't rely on Margin as the primary tool for layouts
❌ Avoid writing UserControls or subclassing to extend a default control -- use Behaviors instead (Microsoft.Xaml.Behaviors.Wpf)

✅ Write XAML by hand and autoformat with "Ctrl K,D" or XAML Styler
✅ Rely upon XAML Hot Reload to design your app's UI at runtime
✅ Use layout controls (Grid, DockPanel, etc) to support proper resizing
✅ Use data binding to eliminate glue code and state synchronization issues
✅ Use collection controls and DataTemplate to dynamically create lists of controls
✅ Learn MVVM to create maintainable apps
✅ Use the Dispatcher to update controls from non-UI threads
✅ WPF's default controls can be easily modernized via $wpfuilibs
✅ Include relevant XAML, code-behind, and ViewModel code for questions when possible
Fluffy
FluffyOP11mo ago
The answer to my own question
private void scrollviewer_Messages_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scrollViewer = sender as ScrollViewer;
if (e.ExtentHeightChange == 0)
{ // Content unchanged : user scroll event
if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
{ // Scroll bar is in bottom
// Set auto-scroll mode
AutoScroll = true;
}
else
{ // Scroll bar isn't in bottom
// Unset auto-scroll mode
AutoScroll = false;
}
}

// Content scroll event : auto-scroll eventually
if (AutoScroll && e.ExtentHeightChange != 0)
{ // Content changed and auto-scroll mode set
// Autoscroll
scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
}
}
private void scrollviewer_Messages_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer scrollViewer = sender as ScrollViewer;
if (e.ExtentHeightChange == 0)
{ // Content unchanged : user scroll event
if (scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight)
{ // Scroll bar is in bottom
// Set auto-scroll mode
AutoScroll = true;
}
else
{ // Scroll bar isn't in bottom
// Unset auto-scroll mode
AutoScroll = false;
}
}

// Content scroll event : auto-scroll eventually
if (AutoScroll && e.ExtentHeightChange != 0)
{ // Content changed and auto-scroll mode set
// Autoscroll
scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
}
}
added this event handler that checks if scroll bar is at the bottom, if it is it enables auto scroll is not it stays
<ScrollViewer x:Name="MessageScroller" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" ScrollChanged="scrollviewer_Messages_ScrollChanged">
<ItemsPresenter />
</ScrollViewer>
<ScrollViewer x:Name="MessageScroller" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" ScrollChanged="scrollviewer_Messages_ScrollChanged">
<ItemsPresenter />
</ScrollViewer>
Added the ScrollChanged which fires the event
Want results from more Discord servers?
Add your server