diff --git a/src/Markdig.Wpf.SampleAppCustomized/Customized/ColumnScalingTableRenderer.cs b/src/Markdig.Wpf.SampleAppCustomized/Customized/ColumnScalingTableRenderer.cs new file mode 100644 index 0000000..afa336d --- /dev/null +++ b/src/Markdig.Wpf.SampleAppCustomized/Customized/ColumnScalingTableRenderer.cs @@ -0,0 +1,142 @@ +using System; +using System.Linq; +using System.Windows; +using Markdig.Renderers.Wpf; +using TableColumnAlign = Markdig.Extensions.Tables.TableColumnAlign; +using Table = Markdig.Extensions.Tables.Table; +using TableCell = Markdig.Extensions.Tables.TableCell; +using TableRow = Markdig.Extensions.Tables.TableRow; +using WpfDocs = System.Windows.Documents; + + +namespace Markdig.Wpf.SampleAppCustomized.Customized +{ + public class ColumnScalingTableRenderer : WpfObjectRenderer + { + protected override void Write(Renderers.WpfRenderer renderer, Table table) + { + if (renderer == null) throw new ArgumentNullException(nameof(renderer)); + if (table == null) throw new ArgumentNullException(nameof(table)); + + var wpfTable = new WpfDocs.Table(); + + wpfTable.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.TableStyleKey); + + #region Customization + + var columnValueList = new System.Collections.Generic.List?[table.ColumnDefinitions.Count]; + + #endregion + + foreach (var tableColumnDefinition in table.ColumnDefinitions) + { + wpfTable.Columns.Add(new WpfDocs.TableColumn + { + Width = (tableColumnDefinition?.Width ?? 0) != 0 ? + new GridLength(tableColumnDefinition!.Width, GridUnitType.Star) : + GridLength.Auto, + }); + } + + var wpfRowGroup = new WpfDocs.TableRowGroup(); + + renderer.Push(wpfTable); + renderer.Push(wpfRowGroup); + + foreach (var rowObj in table) + { + var row = (TableRow)rowObj; + var wpfRow = new WpfDocs.TableRow(); + + renderer.Push(wpfRow); + + if (row.IsHeader) + { + wpfRow.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.TableHeaderStyleKey); + } + + for (var i = 0; i < row.Count; i++) + { + #region Customization + + if (i < columnValueList.Length - 1 && columnValueList[i] is null) + columnValueList[i] = new(row.Count); + + #endregion + + var cellObj = row[i]; + var cell = (TableCell)cellObj; + var wpfCell = new WpfDocs.TableCell + { + ColumnSpan = cell.ColumnSpan, + RowSpan = cell.RowSpan, + }; + + wpfCell.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.TableCellStyleKey); + + renderer.Push(wpfCell); + renderer.Write(cell); + renderer.Pop(); + + var txt = new WpfDocs.TextRange(wpfCell.ContentStart, wpfCell.ContentEnd).Text; + columnValueList[i]?.Add(txt); + + if (table.ColumnDefinitions.Count > 0) + { + var columnIndex = cell.ColumnIndex < 0 || cell.ColumnIndex >= table.ColumnDefinitions.Count + ? i + : cell.ColumnIndex; + columnIndex = columnIndex >= table.ColumnDefinitions.Count ? table.ColumnDefinitions.Count - 1 : columnIndex; + var alignment = table.ColumnDefinitions[columnIndex].Alignment; + + + #region Customization + + if (row.IsHeader) + alignment = TableColumnAlign.Center; + + #endregion + + if (alignment.HasValue) + { + switch (alignment) + { + case TableColumnAlign.Center: + wpfCell.TextAlignment = TextAlignment.Center; + break; + case TableColumnAlign.Right: + wpfCell.TextAlignment = TextAlignment.Right; + break; + case TableColumnAlign.Left: + wpfCell.TextAlignment = TextAlignment.Left; + break; + } + } + } + } + + renderer.Pop(); + } + + #region Customization + + var weights = columnValueList.Select(x => x?.Max(y => y.Length) ?? 0.0).ToArray(); + var sum = weights.Sum(); + for (int i = 0; i < weights.Length; i++) + { + var col = wpfTable.Columns[i]; + var weight = weights[i]; + col.Width = weight == 0 + ? new GridLength(0, GridUnitType.Pixel) + : new GridLength(weight / sum * 100.0, GridUnitType.Star); + } + + #endregion + + renderer.Pop(); + renderer.Pop(); + } + + + } +} \ No newline at end of file diff --git a/src/Markdig.Wpf.SampleAppCustomized/Customized/MarkdownViewer.cs b/src/Markdig.Wpf.SampleAppCustomized/Customized/MarkdownViewer.cs index 8d4888c..b131a4f 100644 --- a/src/Markdig.Wpf.SampleAppCustomized/Customized/MarkdownViewer.cs +++ b/src/Markdig.Wpf.SampleAppCustomized/Customized/MarkdownViewer.cs @@ -5,7 +5,7 @@ namespace Markdig.Wpf.SampleAppCustomized.Customized { /// /// Usually the image paths in the Markdown must be relative to the application or absolute. - /// This classes make it possible to change the root path. + /// This class utilizes a custom renderer and facilitates changing the root path. /// public class MarkdownViewer : Markdig.Wpf.MarkdownViewer { @@ -27,13 +27,30 @@ public string UCRootPath protected override void RefreshDocument() { - // In some cases the path is not updated fast enough, so we force it + Document = Markdown is null + ? null + : Markdig.Wpf.Markdown.ToFlowDocument(Markdown, Pipeline ?? DefaultPipeline, _renderer); + } + + + private WpfRenderer? _renderer = null; + public void SetCustomRenderer(bool? state) + { + // For obvious contrast, we only provide a custom renderer in 1 of the 3 presentation states + if (state != true) + { + _renderer = null; + return; + } + + // In some cases the UCRootPath is not updated fast enough, so we force it this.GetBindingExpression(UCRootPathProperty)?.UpdateTarget(); - + var path = UCRootPath; if (!string.IsNullOrEmpty(path) && !path.EndsWith("/", StringComparison.Ordinal)) path = path.Remove(path.LastIndexOf('/') + 1); - Document = Markdown != null ? Markdig.Wpf.Markdown.ToFlowDocument(Markdown, Pipeline ?? DefaultPipeline, new Customized.WpfRenderer(path)) : null; + + _renderer = new WpfRenderer(new LinkInlineRenderer(path), new ColumnScalingTableRenderer()); } } } diff --git a/src/Markdig.Wpf.SampleAppCustomized/Customized/WpfRenderer.cs b/src/Markdig.Wpf.SampleAppCustomized/Customized/WpfRenderer.cs index c3a68f2..33aef26 100644 --- a/src/Markdig.Wpf.SampleAppCustomized/Customized/WpfRenderer.cs +++ b/src/Markdig.Wpf.SampleAppCustomized/Customized/WpfRenderer.cs @@ -1,24 +1,33 @@ namespace Markdig.Wpf.SampleAppCustomized.Customized { + /// + /// Create a custom Renderer instead of using the one in the Markdig.Wpf package + /// public class WpfRenderer : Markdig.Renderers.WpfRenderer { - private string _linkpath; + private readonly Renderers.IMarkdownObjectRenderer[] _injections; /// /// Initializes the WPF renderer /// - /// image path for the custom LinkInlineRenderer - public WpfRenderer(string linkpath) : base() + /// custom renderer injection list + public WpfRenderer(params Renderers.IMarkdownObjectRenderer[] injectRenderers) : base() { - _linkpath = linkpath; + _injections = injectRenderers; } /// - /// Load first the custom renderer's + /// Load our custom renderer's before the base versions. By doing this, our renderers can + /// handle/continue on that specific Markdig type before ever reaching the default renderer /// protected override void LoadRenderers() { - ObjectRenderers.Add(new LinkInlineRenderer(_linkpath)); + if (_injections.Length > 0) + { + foreach (var renderer in _injections) + ObjectRenderers.Add(renderer); + } + base.LoadRenderers(); } } diff --git a/src/Markdig.Wpf.SampleAppCustomized/MainWindow.xaml b/src/Markdig.Wpf.SampleAppCustomized/MainWindow.xaml index ebc379e..17babc9 100644 --- a/src/Markdig.Wpf.SampleAppCustomized/MainWindow.xaml +++ b/src/Markdig.Wpf.SampleAppCustomized/MainWindow.xaml @@ -6,15 +6,107 @@ xmlns:local="clr-namespace:Markdig.Wpf.SampleAppCustomized.Customized" xmlns:markdig="clr-namespace:Markdig.Wpf;assembly=Markdig.Wpf" mc:Ignorable="d" + DataContext="{Binding RelativeSource={RelativeSource Self}}" Title="MainWindow"> + + + + + + + + + + + -