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));
            }
        }
    }
相关推荐
暖馒7 小时前
Modbus应用层协议的深度剖析
网络·网络协议·c#·wpf·智能硬件
R1nG86310 小时前
HCCL vs NCCL代码级对比 hccl/algorithms/ vs nccl/src/collectives/ Ring算法实现差异
wpf·cann
风指引着方向13 小时前
归约操作优化:ops-math 的 Sum/Mean/Max 实现
人工智能·wpf
听麟16 小时前
HarmonyOS 6.0+ 跨端智慧政务服务平台开发实战:多端协同办理与电子证照管理落地
笔记·华为·wpf·音视频·harmonyos·政务
听麟20 小时前
HarmonyOS 6.0+ APP AR文旅导览系统开发实战:空间定位与文物交互落地
人工智能·深度学习·华为·ar·wpf·harmonyos
聆风吟º1 天前
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