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));
            }
        }
    }
相关推荐
郝学胜-神的一滴19 小时前
AI 编程智能体 27:吃透MCP通信机制
人工智能·python·langchain·wpf·numpy·scikit-learn
波力海苔夹心脆6752 天前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
陈仓主教2 天前
# WPF CheckBox 控件详解与使用—WPF 中的控件(6)--复选框控件(CheckBox)
wpf
光泽雨4 天前
WPF 音视频四大核心方案对比
wpf·音视频
浪扼飞舟4 天前
WPF(数据绑定)
wpf
samble5 天前
从零搭建半导体设备上位机(四):单实例、启动流程与配置文件,App 里那 526 行到底在干什么
wpf·配置文件·单实例
浪扼飞舟6 天前
WPF(控件的继承树、内容控件、布局控件)
wpf
avi91119 天前
电影开源Jevdo - 源码介绍(vue版)没有android 和 没有wpf
android·wpf·框架·数据爬虫·meego·电影管理
吾与谁归in10 天前
C#脚本工具,支持智能提示自动补全(WPF + Roslyn + AvalonEdit)
开发语言·c#·wpf
昂好的day10 天前
WPF 从零入门(上):WPF 是什么、XAML 语法、布局与样式全解
开发语言·c#·wpf