DiffPlex is C# library to generate textual diffs. It targets netstandard1.0+.
The DiffPlex library currently exposes several interfaces and classes for generating diffs:
IDiffer(implemented by theDifferclass) - This is the core diffing class. It exposes the low level functions to generate differences between texts.ISidebySideDiffer(implemented by theSideBySideDifferclass) - This is a higher level interface. It consumes theIDifferinterface and generates aSideBySideDiffModel. This is a model which is suited for displaying the differences of two pieces of text in a side by side view.IThreeWayDiffer(implemented by theThreeWayDifferclass) - This interface provides three-way diff and merge functionality, enabling intelligent merging by comparing a base text with two modified versions to detect changes and conflicts.UnidiffRenderer- A renderer class that generates unified diff (unidiff) format output compatible with Git, patch utilities, and other standard diff tools.
For examples of how to use the API please see the the following projects contained in the DiffPlex solution.
For use of the IDiffer interface see:
SidebySideDiffer.cscontained in theDiffPlexProject.UnidiffFormater.cscontained in theDiffPlex.ConsoleRunnerproject.
For use of the ISidebySideDiffer interface see:
DiffController.csand associated MVC views in theWebDifferprojectTextBoxDiffRenderer.csin theSilverlightDifferproject
For use of the UnidiffRenderer class see:
Program.csin theDiffPlex.ConsoleRunnerproject
vardiff=InlineDiffBuilder.Diff(before,after);varsavedColor=Console.ForegroundColor;foreach(varlineindiff.Lines){switch(line.Type){caseChangeType.Inserted:Console.ForegroundColor=ConsoleColor.Green;Console.Write("+ ");break;caseChangeType.Deleted:Console.ForegroundColor=ConsoleColor.Red;Console.Write("- ");break;default:Console.ForegroundColor=ConsoleColor.Gray;// compromise for dark or light backgroundConsole.Write(" ");break;}Console.WriteLine(line.Text);}Console.ForegroundColor=savedColor;/// <summary>/// Provides methods for generate differences between texts/// </summary>publicinterfaceIDiffer{/// <summary>/// Create a diff by comparing text line by line/// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <param name="ignoreWhiteSpace">if set to <c>true</c> will ignore white space when determining if lines are the same.</param>/// <returns>A DiffResult object which details the differences</returns>DiffResultCreateLineDiffs(stringoldText,stringnewText,boolignoreWhiteSpace);/// <summary>/// Create a diff by comparing text character by character/// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <param name="ignoreWhitespace">if set to <c>true</c> will treat all whitespace characters are empty strings.</param>/// <returns>A DiffResult object which details the differences</returns>DiffResultCreateCharacterDiffs(stringoldText,stringnewText,boolignoreWhitespace);/// <summary>/// Create a diff by comparing text word by word/// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <param name="ignoreWhitespace">if set to <c>true</c> will ignore white space when determining if words are the same.</param>/// <param name="separators">The list of characters which define word separators.</param>/// <returns>A DiffResult object which details the differences</returns>DiffResultCreateWordDiffs(stringoldText,stringnewText,boolignoreWhitespace,char[]separators);/// <summary>/// Create a diff by comparing text in chunks determined by the supplied chunker function./// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <param name="ignoreWhiteSpace">if set to <c>true</c> will ignore white space when determining if chunks are the same.</param>/// <param name="chunker">A function that will break the text into chunks.</param>/// <returns>A DiffResult object which details the differences</returns>DiffResultCreateCustomDiffs(stringoldText,stringnewText,boolignoreWhiteSpace,Func<string,string[]>chunker);/// <summary>/// Create a diff by comparing text line by line/// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <param name="ignoreWhiteSpace">if set to <c>true</c> will ignore white space when determining if lines are the same.</param>/// <param name="ignoreCase">Determine if the text comparision is case sensitive or not</param>/// <param name="chunker">Component responsible for tokenizing the compared texts</param>/// <returns>A DiffResult object which details the differences</returns>DiffResultCreateDiffs(stringoldText,stringnewText,boolignoreWhiteSpace,boolignoreCase,IChunkerchunker);}publicinterfaceIChunker{/// <summary>/// Dive text into sub-parts/// </summary>string[]Chunk(stringtext);}Currently provided implementations:
CharacterChunkerCustomFunctionChunkerDelimiterChunkerLineChunkerLineEndingsPreservingChunkerWordChunker
The UnidiffRenderer class provides functionality to generate unified diff (unidiff) format output, which is the standard format used by Git, patch utilities, and other diff tools.
// Static method for simple usagestringunidiff=UnidiffRenderer.GenerateUnidiff(oldText:"old content",newText:"new content",oldFileName:"file1.txt",newFileName:"file2.txt");// Instance usage with custom settingsvarrenderer=newUnidiffRenderer(contextLines:5);stringunidiff=renderer.Generate(oldText,newText,"before.txt","after.txt");Key features:
- Generates standard unified diff format compatible with Git and patch tools
- Configurable number of context lines around changes
- Support for custom file names in diff headers
- Options to ignore whitespace and case differences
Example output:
--- before.txt
+++ after.txt
@@ -1,4 +1,4 @@
Line 1
-Old line 2
+New line 2 Line 3
Line 4
The IThreeWayDiffer interface provides functionality for three-way diffing and merging, which is essential for merge operations in version control systems or when comparing three versions of text.
/// <summary>/// Responsible for generating three-way differences and merges between texts/// </summary>publicinterfaceIThreeWayDiffer{/// <summary>/// Creates a three-way diff by comparing base, old, and new text line by line./// </summary>ThreeWayDiffResultCreateDiffs(stringbaseText,stringoldText,stringnewText,boolignoreWhiteSpace,boolignoreCase,IChunkerchunker);/// <summary>/// Creates a three-way merge by comparing base, old, and new text line by line./// </summary>ThreeWayMergeResultCreateMerge(stringbaseText,stringoldText,stringnewText,boolignoreWhiteSpace,boolignoreCase,IChunkerchunker);}Three-way diffing compares three versions of text:
- Base text: The common ancestor or original version
- Old text: One modified version (e.g., your changes)
- New text: Another modified version (e.g., incoming changes)
This enables intelligent merging by identifying:
- Changes unique to the old version
- Changes unique to the new version
- Changes made to both versions (conflicts)
- Unchanged sections
varthreeWayDiffer=newThreeWayDiffer();// Three-way diffvardiffResult=threeWayDiffer.CreateDiffs(baseText,oldText,newText,ignoreWhiteSpace:false,ignoreCase:false,newLineChunker());// Three-way merge with automatic conflict detectionvarmergeResult=threeWayDiffer.CreateMerge(baseText,oldText,newText,ignoreWhiteSpace:false,ignoreCase:false,newLineChunker());// Check for conflictsif(mergeResult.HasConflicts){Console.WriteLine($"Found {mergeResult.ConflictBlocks.Count} conflicts");}else{Console.WriteLine("Merge completed successfully");Console.WriteLine(mergeResult.MergedText);}/// <summary>/// Provides methods that generate differences between texts for displaying in a side by side view./// </summary>publicinterfaceISideBySideDiffBuilder{/// <summary>/// Builds a diff model for displaying diffs in a side by side view/// </summary>/// <param name="oldText">The old text.</param>/// <param name="newText">The new text.</param>/// <returns>The side by side diff model</returns>SideBySideDiffModelBuildDiffModel(stringoldText,stringnewText);}DiffPlex also contains a sample website that shows how to create a basic side by side diff in an ASP MVC website.
DiffPlex includes a Blazor sample application demonstrating how to render textual diffs in modern Blazor applications. The sample showcases both server-side and client-side rendering capabilities with interactive diff visualization.
The Blazor components provide:
- Interactive side-by-side diff rendering
- Inline diff view mode
- Unififf rendering
- Three-way merge

To run the sample Blazor application:
cd DiffPlex.Blazor
dotnet runThere are 2 libraries for Windows app development. One is for Windows App SDK, another is for WPF and WinForms.
DiffPlex WinUI library DiffPlex.Windows is used to render textual diffs in your app which targets to Windows App SDK.
usingDiffPlex.UI;And insert following code into the root node of your xaml file, e.g. user control, page or window.
xmlns:diffplex="using:DiffPlex.UI"
DiffTextViewTextual diffs view element.
For example.
<diffplex:DiffTextViewx:Name="DiffView" />DiffView.SetText(OldText,NewText);You can also customize the style. Following are some of the properties you can get or set.
// true if it is in split view; otherwise, false, in unified view.publicboolIsSplitView{get;set;}// true if it is in unified view; otherwise, false, in split view.publicboolIsUnifiedView{get;set;}// The selection mode of list view. Default is None.publicListViewSelectionModeSelectionMode{get;set;}// true if ignore white spaces; otherwise, false. Default is true.publicboolIgnoreWhiteSpace{get;set;}// true if the text is case sensitive; otherwise, false. Default is false.publicboolIsCaseSensitive{get;set;}// The default text color (foreground brush).publicBrushForeground{get;set;}// The background.publicBrushBackground{get;set;}// The width of the line number. Default is 50.publicGridLengthLineNumberWidth{get;set;}// The style of the line number.publicStyleLineNumberStyle{get;set;}// The width of the change type symbol. Default is 20.publicGridLengthChangeTypeWidth{get;set;}// The style of the change type symbol.publicStyleChangeTypeStyle{get;set;}// The style of the text.publicStyleTextStyle{get;set;}// true if the text is selection enabled; otherwise, false. Default is true.publicboolIsTextSelectionEnabled{get;set;}// true if collapse unchanged sections; otherwise, false. Default is false.publicboolIsUnchangedSectionCollapsed{get;set;}// The lines for context. Default is 2.publicintLineCountForContext{get;set;}// true if the file selector menu button is enabled; otherwise, false. Default is true.publicboolIsFileMenuEnabled{get;set;}// The height of command bar. Default is 50.publicGridLengthCommandBarHeight{get;set;}// The default label position of command bar. Default is Right.publicCommandBarDefaultLabelPositionCommandLabelPosition{get;set;}// The collection of secondary command elements for the command bar.publicIObservableVector<ICommandBarElement>SecondaryCommands{get;}DiffPlex WPF control library DiffPlex.Wpf is used to render textual diffs in your WPF application.
It targets .NET 9, .NET 8, .NET 6, .NET Framework 4.8 and .NET Framework 4.6.
usingDiffPlex.Wpf.Controls;To import the controls into your window/page/control, please insert following attribute into the root node (such as <Window />) of your xaml files.
xmlns:diffplex="clr-namespace:DiffPlex.Wpf.Controls;assembly=DiffPlex.Wpf"
DiffViewerTextual diffs viewer control with view mode switching by setting an old text and a new text to diff.SideBySideDiffViewerSide-by-side (splitted) textual diffs viewer control by setting a diff modelSideBySideDiffModel.InlineDiffViewerInline textual diffs viewer control by setting a diff modelDiffPaneModel.
For example.
<diffplex:DiffViewerx:Name="DiffView" />DiffView.OldText=oldText;DiffView.NewText=newText;You can also customize the style. Following are some of the properties you can get or set.
// The header of old text.publicstringOldTextHeader{get;set;}// The header of new text.publicstringNewTextHeader{get;set;}// true if it is in side-by-side (split) view;// otherwise, false, in inline (unified) view.publicboolIsSideBySideViewMode{get;}// true if collapse unchanged sections; otherwise, false.publicboolIgnoreUnchanged{get;set;}// Hides the line numbers.publicboolHideLineNumbers{get;set;}// The font size.publicdoubleFontSize{get;set;}// The preferred font family.publicFontFamilyFontFamily{get;set;}// The font weight.publicFontWeightFontWeight{get;set;}// The font style.publicFontStyleFontStyle{get;set;}// The font-stretching characteristics.publicFontStretchFontStretch{get;set;}// The default text color (foreground brush).publicBrushForeground{get;set;}// The background brush of the line inserted.publicBrushInsertedBackground{get;set;}// The background brush of the line deleted.publicBrushDeletedBackground{get;set;}// The text color (foreground brush) of the line number.publicBrushLineNumberForeground{get;set;}// The width of the line number and change type symbol.publicintLineNumberWidth{get;set;}// The background brush of the line imaginary.publicBrushImaginaryBackground{get;set;}// The text color (foreground brush) of the change type symbol.publicBrushChangeTypeForeground{get;set;}// The background brush of the header.publicBrushHeaderBackground{get;set;}// The height of the header.publicdoubleHeaderHeight{get;set;}// The background brush of the grid splitter.publicBrushSplitterBackground{get;set;}// The width of the grid splitter.publicThicknessSplitterWidth{get;set;}// A value that represents the actual calculated width of the left side panel.publicdoubleLeftSideActualWidth{get;}// A value that represents the actual calculated width of the right side panel.publicdoubleRightSideActualWidth{get;}And you can listen following event handlers.
// Occurs when the grid splitter loses mouse capture.publiceventDragCompletedEventHandler SplitterDragCompleted;// Occurs one or more times as the mouse changes position when the grid splitter has logical focus and mouse capture.publiceventDragDeltaEventHandler SplitterDragDelta;// Occurs when the grid splitter receives logical focus and mouse capture.publiceventDragStartedEventHandler SplitterDragStarted;// Occurs when the view mode is changed.publiceventEventHandler<ViewModeChangedEventArgs> ViewModeChanged;Windows Forms control of diff viewer is a WPF element host control.
It is also included in DiffPlex.Wpf assembly.
You can import it to use in your Windows Forms application.
It targets .NET 8, .NET 6, .NET Framework 4.8 and .NET Framework 4.6.
usingDiffPlex.WindowsForms.Controls;Then you can add the following control in window or user control.
DiffViewerTextual diffs viewer control with view mode switching by setting an old text and a new text to diff.
For example.
publicpartialclassForm1:Form{publicForm1(){InitializeComponent();vardiffView=newDiffViewer{Margin=newPadding(0),Dock=DockStyle.Fill,OldText=oldText,NewText=newText};Controls.Add(diffView);}}You can also customize the style. Following are some of the properties you can get or set.
// The header of old text.publicstringOldTextHeader{get;set;}// The header of new text.publicstringNewTextHeader{get;set;}// true if it is in side-by-side (split) view;// otherwise, false, in inline (unified) view.publicboolIsSideBySideViewMode{get;}// true if collapse unchanged sections; otherwise, false.publicboolIgnoreUnchanged{get;set;}// The font size.publicdoubleFontSize{get;set;}// The preferred font family names in string.publicstringFontFamilyNames{get;set;}// The font weight.publicintFontWeight{get;set;}// The font style.publicboolIsFontItalic{get;set;}// The default text color (foreground brush).publicColorForeColor{get;set;}// The background brush of the line inserted.publicColorInsertedBackColor{get;set;}// The background brush of the line deleted.publicColorDeletedBackColor{get;set;}// The text color (foreground color) of the line number.publicColorLineNumberForeColor{get;set;}// The width of the line number and change type symbol.publicintLineNumberWidth{get;set;}// The background brush of the line imaginary.publicColorImaginaryBackColor{get;set;}// The text color (foreground color) of the change type symbol.publicColorChangeTypeForeColor{get;set;}// The background brush of the header.publicColorHeaderBackColor{get;set;}// The height of the header.publicdoubleHeaderHeight{get;set;}// The background brush of the grid splitter.publicColorSplitterBackColor{get;set;}// The width of the grid splitter.publicPaddingSplitterWidth{get;set;}// A value that represents the actual calculated width of the left side panel.publicdoubleLeftSideActualWidth{get;}// A value that represents the actual calculated width of the right side panel.publicdoubleRightSideActualWidth{get;}



