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));
            }
        }
    }
相关推荐
fogota2 小时前
C# WPF 按钮加载字体图标 / 动物头像
c#·.net·wpf
fogota2 小时前
C# WPF 按钮加载系统图标 / 动物头像
c#·.net·wpf
军训猫猫头2 小时前
C# 封装 MySQL 自动写入与查询工具类(基于 MySqlConnector)
mysql·c#·.net·wpf
gis开发之家1 天前
Spring Boot 4 定时任务与异步线程池:从 @Scheduled 到高并发任务编排(生产级实战)
java·spring boot·后端·wpf·spring boot4
clz13145212 天前
如何设计一个优雅可靠的金融级联机接口
wpf
闲云自留地3 天前
云平台存储管理员:Cinder 创建挂载卷 + Swift 分布式存储原理
分布式·wpf·swift
敲代码的嘎仔4 天前
从集群锁失效到异步领券:我用分布式锁 + Redisson + MQ 把领券接口 RT 从 200ms 压到 15ms
java·数据库·redis·分布式·缓存·ai·wpf
闲云自留地4 天前
OpenStack 的身份管家:Keystone 令牌、RBAC 权限模型拆解
wpf·openstack
FuckPatience6 天前
WPF 窗体唤醒,判断是否已存在,存在则弹出
wpf
程序员清风6 天前
从单体应用到微服务:后端系统拆分的基本方法
微服务·架构·wpf