WPF----自定义滚动条ScrollViewer

滚动条是项目当中经常用到的一个控件,大部分对外项目都有外观的需求,因此需要自定义,文中主要是针对一段动态的状态数据进行展示,并保证数据始终在最新一条,就是需要滚动条滚动到底部。

1,xaml中引入
cs 复制代码
 <ItemsControl Grid.Row="1" Grid.Column="0" ItemsSource="{Binding ProcessList}" >
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <!-- 绑定到数组的每个元素 -->
             <TextBlock Text="{Binding }" Foreground="#fff" Margin="4"/>
         </DataTemplate>
     </ItemsControl.ItemTemplate>
     <ItemsControl.Template>
         <ControlTemplate TargetType="ItemsControl">
             <ScrollViewer x:Name="ScrollViewer" VerticalScrollBarVisibility="Auto"  Loaded="ScrollViewer_Loaded" >
                 <ItemsPresenter/>
             </ScrollViewer>
         </ControlTemplate>
     </ItemsControl.Template>
 </ItemsControl>

也可以直接将ScrollViewer放在所用控件的最外层。

VerticalScrollBarVisibility="Auto" 设置为auto可实现超过区域高度自动展示滚动条。

2,具体样式,放到资源中
cs 复制代码
 <Style TargetType="ScrollBar">
     <Setter Property="Width" Value="8"/>
      <!--设置滚动条宽度--> 
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="ScrollBar">
                 <Grid Background="#212222 " Width="14" SnapsToDevicePixels="true" >
                     <Grid.RowDefinitions>
                         <!--<RowDefinition Height="Auto"/>-->
                         <RowDefinition Height="*"/>
                         <!--<RowDefinition Height="Auto"/>-->
                     </Grid.RowDefinitions>
                      <!--减少按钮--> 
                     <!--<RepeatButton Grid.Row="0" Command="ScrollBar.LineUpCommand" Content="^" Width="10" Height="10"/>-->
                      <!--轨道和滑块-->
                     <Track Grid.Row="1" Name="PART_Track"  Width="14" IsDirectionReversed="True">
                         <Track.Thumb>
                             <Thumb>
                                 <Thumb.Template>
                                     <ControlTemplate>
                                         <Border CornerRadius="2">
                                             <Rectangle  Fill="#82E4E4" RadiusX="2" RadiusY="2" Width="6"/>
                                             <!--<Thumb Width="6" Background="#82E4E4" BorderThickness="0" />-->
                                         </Border>
                                         <!--<Rectangle  Fill="#82E4E4" Width="8"/>-->
                                        
                                     </ControlTemplate>
                                 </Thumb.Template>
                             </Thumb>
                         </Track.Thumb>
                         <Track.DecreaseRepeatButton>
                             <RepeatButton Command="ScrollBar.PageUpCommand" Opacity="0"/>
                         </Track.DecreaseRepeatButton>
                         <Track.IncreaseRepeatButton>
                             <RepeatButton Command="ScrollBar.PageDownCommand" Opacity="0"/>
                         </Track.IncreaseRepeatButton>
                     </Track>
                      <!--增加按钮--> 
                     <!--<RepeatButton Grid.Row="2" Command="ScrollBar.LineDownCommand" Content="v"  Width="10" Height="10"/>-->
                 </Grid>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>
    

设置样式时候注意点:

IsDirectionReversed="True" 设置为true是保证滚动滑块随着鼠标向下滑动,为false的时候正好相反。

轨道的颜色宽度设置等,直接在Grid上面设置就好。

滑块这里用了个Rectangle,可以设置填充色,圆角、宽度等

我这边不需要上下按钮我就注释掉了。

3,滚动条始终保持在底部,在xaml.cs中实现

需要监听 ProcessList 集合的变化,并在每次添加新项后滚动到 ScrollViewer 的底部。

cs 复制代码
 public partial class F0Procedure : Page
 {
     public F0ProcedureViewModel F0ProcedureViewModel {  get; set; }
     private ScrollViewer _scrollViewer;
     public F0Procedure()
     {
         InitializeComponent();
         F0ProcedureViewModel = new F0ProcedureViewModel();
         this.DataContext = F0ProcedureViewModel;
         ((INotifyCollectionChanged)F0ProcedureViewModel.ProcessList).CollectionChanged += F0Procedure_CollectionChanged;
     }

     private void F0Procedure_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
     {
         if (e.Action == NotifyCollectionChangedAction.Add && _scrollViewer != null)
         {
             Application.Current.Dispatcher.Invoke(() =>
             {
                 Console.WriteLine(ScrollViewer.ExtentHeightProperty);
                 _scrollViewer.ScrollToVerticalOffset(_scrollViewer.ExtentHeight);
             });
         }
     }
     private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
     {
         _scrollViewer = sender as ScrollViewer;
     }
 }

我这的ProcessList是委托回调更新的,

cs 复制代码
[ObservableProperty]
private int _progressValue;


public void  UpdateExecutionProgress(string process)
{
    Application.Current.Dispatcher.BeginInvoke(new Action(() => ProcessList.Add(process)));
}

可以用 DispatcherTimer模拟,博客里也有讲过,这边都是引用的CommunityToolKit MVVM库。

4,最终结果

用到哪,学到哪,今天又是满满收获的一天。

相关推荐
wyh要好好学习25 分钟前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf
lgcgkCQ16 小时前
任务调度中心-XXL-JOB使用详解
java·wpf·定时任务·任务调度
Vicky&James16 小时前
英雄联盟客户端项目:从跨平台Uno Platform到Win UI3的转换只需要30分钟
github·wpf·跨平台·英雄联盟·winui·unoplatform
就是有点傻1 天前
WPF中如何使用区域导航
wpf
她说彩礼65万1 天前
WPF程序设置单例启动(互斥体)
wpf
就是有点傻1 天前
WPF中Prism框架中 IContainerExtension 和 IRegionManager的作用
wpf
月落.1 天前
WPF中MVVM工具包 CommunityToolkit.Mvvm
wpf·mvvm
月落.1 天前
WPF Prism框架
wpf·prism
Crazy Struggle2 天前
.NET 8.0 通用管理平台,支持模块化、WinForms 和 WPF
vue·wpf·winform·.net 8.0·通用权限管理
呆萌很3 天前
HCIP-HarmonyOS Application Developer 习题(二十)
华为·wpf·harmonyos