WPF-自动滚动文本控件

效果图:

控件功能:根据文本自动换行,每增加一行,自动滚动到最后一行。

封装过程使用NuGet

复制代码
  <ItemGroup>
    <PackageReference Include="DevExpressMvvm" Version="24.1.6" />
    <PackageReference Include="ValueConverters" Version="3.1.22" />
  </ItemGroup>

代码部分:

  1. StringToColorConvert.cs

    cs 复制代码
    using System.Windows.Media;
    using System.Globalization;
    using System.Reflection;
    using System.Windows.Data;
    
    namespace WPFApp
    {
        public class StringToColorConvert : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                Dictionary<string, string> colorDic = parameter.ToString().Split(';', StringSplitOptions.RemoveEmptyEntries).Where(s=>s.Contains(':')).ToDictionary(s => s.Split(':')[0], s => s.Split(':')[1]);
                Brush brush = Brushes.Black;
                if (value == null)
                {
                    return brush;
                }
                if (colorDic.TryGetValue(value.ToString(), out string dicValue))
                {
                    PropertyInfo colorProperty = typeof(Brushes).GetProperty(dicValue, BindingFlags.Public | BindingFlags.Static | BindingFlags.IgnoreCase);
                    if (colorProperty != null)
                    {
                        brush = (Brush)colorProperty.GetValue(null);
                    }
                }
                return brush;
    
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
  2. App.xaml

    cs 复制代码
    <Application
        x:Class="WPFApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFApp"
        StartupUri="MainWindow.xaml">
        <Application.Resources>
            <local:StringToColorConvert x:Key="StringToColorConvert" />
            <Style TargetType="{x:Type local:LogControl}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type local:LogControl}">
                            <Border
                                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalAlignment}"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                                <ItemsControl
                                    x:Name="PART_ItemsControl"
                                    HorizontalAlignment="Stretch"
                                    VerticalAlignment="Stretch"
                                    ItemsSource="{TemplateBinding Items}">
                                    <ItemsControl.Template>
                                        <ControlTemplate TargetType="ItemsControl">
                                            <ScrollViewer Name="scrollViewer" VerticalScrollBarVisibility="Auto">
                                                <StackPanel>
                                                    <ItemsPresenter />
                                                </StackPanel>
                                            </ScrollViewer>
                                        </ControlTemplate>
                                    </ItemsControl.Template>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="Auto" />
                                                    <RowDefinition Height="Auto" />
                                                </Grid.RowDefinitions>
                                                <!--  文本  -->
                                                <TextBlock
                                                    Grid.Row="0"
                                                    Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ActualWidth}"
                                                    Padding="0,3,0,1"
                                                    VerticalAlignment="Center"
                                                    Foreground="{Binding Item2, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource StringToColorConvert}, ConverterParameter='0:Black;1:Green;2:Red;'}"
                                                    Text="{Binding Item1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                                                    TextTrimming="CharacterEllipsis"
                                                    ToolTip="{Binding Text, RelativeSource={RelativeSource Mode=Self}}">
                                                    <TextBlock.Style>
                                                        <Style TargetType="TextBlock">
                                                            <Style.Triggers>
                                                                <Trigger Property="IsMouseOver" Value="True">
                                                                    <Setter Property="Background" Value="#bee6fd" />
                                                                </Trigger>
                                                            </Style.Triggers>
                                                        </Style>
                                                    </TextBlock.Style>
                                                </TextBlock>
                                                <!--  下划线  -->
                                                <Border
                                                    Grid.Row="1"
                                                    Height="0.2"
                                                    Background="Black" />
                                            </Grid>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Application.Resources>
    </Application>
  3. LogControl.cs

    cs 复制代码
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace WPFApp
    {
        [TemplatePart(Name = LOGItemsControl, Type = typeof(ItemsControl))]
    
        public class LogControl:UserControl
        {
            public const string LOGItemsControl = "PART_ItemsControl";
            private ItemsControl logItemsControl;
    
            public ObservableCollection<Tuple<string, int>> Items
            {
                get { return (ObservableCollection<Tuple<string, int>>)GetValue(ItemsProperty); }
                set { SetValue(ItemsProperty, value); }
            }
    
            public static readonly DependencyProperty ItemsProperty =
                DependencyProperty.Register(nameof(Items), typeof(ObservableCollection<Tuple<string, int>>), typeof(LogControl), new PropertyMetadata(default, (d, e) =>
                {
                    var control = (LogControl)d;
                    if (e.NewValue != null && control.Items != null)
                    {
                        control.Items.CollectionChanged += (sender, args) =>
                        {
                            if (args.Action != NotifyCollectionChangedAction.Add) return;
                            control.Dispatcher.InvokeAsync(() =>
                            {
                                control.ScrollToEnd();
                            });
                        };
                    }
                }));
    
            public override void OnApplyTemplate()
            {
                logItemsControl = GetTemplateChild(LOGItemsControl) as ItemsControl;
                base.OnApplyTemplate();
            }
    
            private void ScrollToEnd()
            {
                var scrollViewer = FindScrollViewer(logItemsControl);
                if (scrollViewer != null)
                {
                    scrollViewer.ScrollToEnd();
                }
            }
    
            public ScrollViewer FindScrollViewer(ItemsControl itemsControl)
            {
                var templateRoot = itemsControl.Template.FindName("scrollViewer", itemsControl) as ScrollViewer;
                if (templateRoot != null)
                {
                    return templateRoot;
                }
                return FindVisualChild<ScrollViewer>(itemsControl);
            }
    
            private T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
                {
                    var child = VisualTreeHelper.GetChild(parent, i);
                    if (child is T)
                    {
                        return (T)child;
                    }
                    var foundChild = FindVisualChild<T>(child);
                    if (foundChild != null)
                    {
                        return foundChild;
                    }
                }
                return null;
            }
        }
    }

使用 :

  1. MainWindow.xaml

    cs 复制代码
    <Window
        x:Class="WPFApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:WPFApp"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="800"
        Height="450"
        mc:Ignorable="d">
        <Window.DataContext>
            <local:MainWindowViewModel />
        </Window.DataContext>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <local:LogControl Items="{Binding Items}" />
            <Button
                Grid.Row="1"
                Click="{DXEvent 'AddItems()'}"
                Content="测试" />
        </Grid>
    </Window>
  2. MainWindowViewModel.cs

    cs 复制代码
    using System.Collections.ObjectModel;
    using ValueConverters;
    
    namespace WPFApp
    {
        public class MainWindowViewModel : BindableBase
        {
            private ObservableCollection<Tuple<string, int>> items;
    
    
            public ObservableCollection<Tuple<string, int>> Items
            {
                get { return items; }
                set { SetProperty(ref items, value); }
            }
    
            public MainWindowViewModel()
            {
                Items = new ObservableCollection<Tuple<string, int>>()
                {
                    new Tuple<string, int>("This is normal message",0),
                    new Tuple<string, int>("This is success message",1),
                    new Tuple<string, int>("This is error message",2),
                };
            }
    
            public void AddItems()
            {
                Items.Add(new Tuple<string, int> ("This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long message", 1));
            }
        }
    }
相关推荐
李高钢21 小时前
开源控件库 HandyControl 介绍与简单实践:让 WPF 界面告别“上个世纪“
开源·wpf
旋生万物1 天前
【终极实战】用Python从零“生成“一个宇宙:螺旋干涉模型的代码实现
开发语言·前端·人工智能·react.js·php·wpf
Now喔2 天前
WPF画刷介绍
wpf
李高钢2 天前
WPF/WinForms 客户端通过 gRPC 与后端通信:从 Proto 契约到流式调用的完整指南
wpf·grpc·winforms
一见已难忘3 天前
基于 Harmony 6.0 应用的宠物寄养预约系统实现
wpf·宠物
fl1768313 天前
基于C#WPF实现的内存加速球清理类似360加速球内存清理
开发语言·c#·wpf
李高钢3 天前
【WPF】高级 UI 与性能优化实战:从卡顿到丝滑
ui·性能优化·wpf
Chris _data4 天前
WPF 上位机开发学习笔记 - 第四天
笔记·学习·wpf
李高钢4 天前
除了 IDE,C#/WPF 开发者每天离不开的 10 个工具
ide·c#·wpf
李高钢4 天前
用 JetBrains Rider 写 WPF 的 15 个高效技巧:从 VS 转过来也值得看
wpf