V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yanjinhua
V2EX  ›  C#

如何实现 WPF 代码查看器控件

  •  
  •   yanjinhua · 2023-01-12 11:21:28 +08:00 · 1224 次点击
    这是一个创建于 706 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如何实现 WPF 代码查看器控件

    CodeViewer

    作者:WPFDevelopersOrg - 驚鏵

    原文链接https://github.com/WPFDevelopersOrg/WPFDevelopers

    • 框架使用.NET40
    • Visual Studio 2019;
    • 代码展示需要使用到AvalonEdit是基于WPF的代码显示控件,项目地址,支持C#javascript,C++,XML,HTML,Java等语言的关键字高亮显示。
    • AvalonEdit也是支持自定义的高亮配置,对于需要编写脚本编辑器的场景非常适用。
    • 可通过配置CustomHighlighting.xshd文件,可以对高亮显示做自定义设置。
    • 以下能够实现ifelse高亮格式设置,代码如下:
    <?xml version="1.0"?>
    <SyntaxDefinition name="Custom Highlighting" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
        <RuleSet>
            <Keywords fontWeight="bold" foreground="Blue">
                <Word>if</Word>
                <Word>else</Word>
            </Keywords>
        </RuleSet>
    </SyntaxDefinition>
    

    1 )新建 SourceCodeModel.cs用作记录代码源码地址源码类型等。

    namespace WPFDevelopers.Samples.Controls
    {
        public class SourceCodeModel
        {
            public CodeType CodeType { get; set; }
            public string Haader { get; set; }
    
            public string CodeSource { get; set; }
    
        }
        public enum CodeType
        {
            Xaml,
            CSharp,
        }
    }
    

    2 )新建 CodeViewer.xaml 代码如下:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls">
        <Style TargetType="{x:Type controls:CodeViewer}">
            <Setter Property="FontSize" Value="{StaticResource NormalFontSize}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type controls:CodeViewer}">
                        <TabControl x:Name="PART_TabControl">
                            <TabControl.Resources>
                                <Style TargetType="TabPanel">
                                    <Setter Property="HorizontalAlignment" Value="Right"/>
                                </Style>
                            </TabControl.Resources>
                            <TabItem x:Name="PART_TabItemContent" Header="Sample" Content="{TemplateBinding Content}"/>
                            
                        </TabControl>
                        <ControlTemplate.Triggers>
                            <Trigger Property="Content" Value="{x:Null}">
                                <Setter Property="Visibility" TargetName="PART_TabItemContent" Value="Collapsed"/>
                                <Setter Property="SelectedIndex" TargetName="PART_TabControl" Value="1"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    

    3 )新建 CodeViewer.cs 继承ContentControl 代码如下:

    • Content用来展示控件。
    • 增加公共集合属性用做存放代码信息SourceCodes,重写控件时循环SourceCodes增加TabItemPART_TabControl中。
    using ICSharpCode.AvalonEdit;
    using ICSharpCode.AvalonEdit.Editing;
    using ICSharpCode.AvalonEdit.Highlighting;
    using System;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Windows;
    using System.Windows.Controls;
    using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;
    
    namespace WPFDevelopers.Samples.Controls
    {
        [TemplatePart(Name = TabControlTemplateName, Type = typeof(TabControl))]
        public class CodeViewer : ContentControl
        {
            private static readonly Type _typeofSelf = typeof(CodeViewer);
            public ObservableCollection<SourceCodeModel> SourceCodes { get; } = new ObservableCollection<SourceCodeModel>();
            private const string TabControlTemplateName = "PART_TabControl";
            private TabControl _tabControl = null;
            static CodeViewer()
            {
                DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf,
                    new FrameworkPropertyMetadata(_typeofSelf));
            }
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    
                _tabControl = GetTemplateChild(TabControlTemplateName) as TabControl;
                foreach (var item in SourceCodes)
                {
                    var tabItem = CreateTabItem(item);
                    _tabControl.Items.Add(tabItem);
                }
            }
            TabItem CreateTabItem(SourceCodeModel codeModel)
            {
                if(codeModel== null)return null;
                var partTextEditor = new TextEditor();
                partTextEditor.Options = new TextEditorOptions { ConvertTabsToSpaces = true };
                partTextEditor.TextArea.SelectionCornerRadius = 0;
                partTextEditor.SetResourceReference(TextArea.SelectionBrushProperty, "WindowBorderBrushSolidColorBrush");
                partTextEditor.TextArea.SelectionBorder = null;
                partTextEditor.TextArea.SelectionForeground = null;
                partTextEditor.IsReadOnly = false;
                partTextEditor.ShowLineNumbers = true;
                partTextEditor.FontFamily = DrawingContextHelper.FontFamily;
                partTextEditor.Text = GetCodeText(codeModel.CodeSource);
                var tabItem = new TabItem
                {
                    Content = partTextEditor
                };
                switch (codeModel.CodeType)
                {
                    case CodeType.Xaml:
                        partTextEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".XML");
                        tabItem.Header = codeModel.Haader == null ? "Xaml" : codeModel.Haader;
                        break;
                    case CodeType.CSharp:
                        partTextEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".CS");
                        tabItem.Header = codeModel.Haader == null ? "CSharp" : codeModel.Haader;
                        break;
                }
                
                return tabItem;
            }
            string GetCodeText(string codeSource)
            {
                var code = string.Empty;
                var uri = new Uri(codeSource, UriKind.Relative);
                var resourceStream = Application.GetResourceStream(uri);
                if (resourceStream != null)
                {
                    var streamReader = new StreamReader(resourceStream.Stream);
                    code = streamReader.ReadToEnd();
                    return code;
                }
                return code;
            }
        }
    }
    
    

    4 )新建 WPFDevelopers.SamplesCode.csproj 项目,在VS右键项目添加现有项目将所需要读取的代码文件添加为链接就能得到以下地址:

    <Resource Include="..\WPFDevelopers.Samples\ExampleViews\AnimationNavigationBar3DExample.xaml">
    		  <Link>ExampleViews\AnimationNavigationBar3DExample.xaml</Link>
    </Resource>
    

    4 )修改Example 代码如下:

    <UserControl x:Class="WPFDevelopers.Samples.ExampleViews.AnimationNavigationBar3DExample"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
                 xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls"
                 xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
        <controls:CodeViewer>
           <!--此处放展示控件-->
            <controls:CodeViewer.SourceCodes>
                <controls:SourceCodeModel 
                    CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/AnimationNavigationBar3DExample.xaml" 
                    CodeType="Xaml"/>
                <controls:SourceCodeModel 
                    CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/AnimationNavigationBar3DExample.xaml.cs" 
                    CodeType="CSharp"/>
            </controls:CodeViewer.SourceCodes>
        </controls:CodeViewer>
    </UserControl>
    

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3005 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 14:07 · PVG 22:07 · LAX 06:07 · JFK 09:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.