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,最终结果

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

相关推荐
暖馒9 小时前
Modbus应用层协议的深度剖析
网络·网络协议·c#·wpf·智能硬件
R1nG86311 小时前
HCCL vs NCCL代码级对比 hccl/algorithms/ vs nccl/src/collectives/ Ring算法实现差异
wpf·cann
风指引着方向15 小时前
归约操作优化:ops-math 的 Sum/Mean/Max 实现
人工智能·wpf
听麟18 小时前
HarmonyOS 6.0+ 跨端智慧政务服务平台开发实战:多端协同办理与电子证照管理落地
笔记·华为·wpf·音视频·harmonyos·政务
听麟1 天前
HarmonyOS 6.0+ APP AR文旅导览系统开发实战:空间定位与文物交互落地
人工智能·深度学习·华为·ar·wpf·harmonyos
聆风吟º2 天前
CANN hccl 深度解析:异构计算集群通信库的跨节点通信与资源管控实现逻辑
人工智能·wpf·transformer·cann
无心水2 天前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf
LZL_SQ2 天前
HCCL测试框架中AllReduce边界条件测试设计深度剖析
wpf·cann
User_芊芊君子3 天前
【分布式训练】CANN SHMEM跨设备内存通信库:构建高效多机多卡训练的关键组件
分布式·深度学习·神经网络·wpf
就是有点傻4 天前
WPF按钮走马灯效果
wpf