whistyun / MdXaml

Markdown for WPF - alternate version of Markdown.Xaml
MIT License
245 stars 37 forks source link

Navigating to another markdown file, and anchors #77

Open RupertAvery opened 1 year ago

RupertAvery commented 1 year ago

Right now I have a singel markdown file, but it's getting large and I'd lke to break it up into smaller files and be able to navigate between them.

Suppose I have links to other markdown files relative to the current. I couldn't seem to find a way to implement navigation to other markdown files, and I suppose it makes senst that external navigation is not part of this library.

Right now, I have it binding to a model and the Markdown binding to CurrentPage.

            <mdXaml:MarkdownScrollViewer 
                x:Name="MarkdownScrollViewer"
                VerticalAlignment="Stretch"
                HorizontalAlignment="Stretch"
                Background="White"
                MarkdownStyle="{Binding Style}"
                Markdown="{Binding CurrentPage}">
            </mdXaml:MarkdownScrollViewer>

Then I load the text into CurrentPage.

            var path = "Help\\Index.md";

            var model = new HelpModel
            {
                CurrentPage = File.ReadAllText(path),
                CurrentPath = "Help",
                Style = CustomStyles.BetterGithub,
                Escape = new RelayCommand<object>(o => Close())
            };

            MarkdownScrollViewer.Engine = new Markdown()
            {
                HyperlinkCommand = new CustomLinkCommand(model),
            };

I have a CustomLinkCommand that takes the model, so I can load a new page when I intercept a relative link.


    public class CustomLinkCommand : ICommand
    {
        private readonly HelpModel _model;

        public event EventHandler CanExecuteChanged;

        public CustomLinkCommand(HelpModel model)
        {
            _model = model;
        }

        public bool CanExecute(object parameter) => true;

        public void Execute(object parameter)
        {
            var href = (string)parameter;

            try
            {
                if (href.StartsWith("https:"))
                {
                    Process.Start(new ProcessStartInfo(href)
                    {
                        UseShellExecute = true,
                        Verb = "open"
                    });
                }
                else
                {
                    href = href.Replace("%20", " ");
                    href = href.Replace("/", "\\");

                    var file = Path.GetFullPath(Path.Combine(_model.CurrentPath, href));
                    _model.CurrentPath = Path.GetFullPath(Path.GetDirectoryName(file));

                    if (File.Exists(file))
                    {
                        _model.CurrentPage = File.ReadAllText(file);
                    }
                }

            }
            catch
            {
                // error handle; notifications, path changes, etc. 
                // MessageBox.Show($"Failed to open {href}");
            }
        }
    }

This kind of works, but now I am unable to link to an anchor (e.g. #some-anchor), and obviously I can't link to an anchor in another markdown with ./Some%20Page.md#some-anchor .

If I could somehow let the viewer handle the link if I detect an anchor, it would be okay, which leaves the anchor in another markdown, maybe if you could expose some event that executes on load / render, and a command to navigate to an anchor programatically.

Or am I thinking about this wrong?

RupertAvery commented 1 year ago

I see that FlowDocumentJumpAnchorIfNecessary has the functionality I need, and it is exactly as I thought it would be implemented.

However, looking further at the source code it looks like it should be able to navigate to different files, but I"m not sure if it works with relative paths?

If I set the Source directly with an URI instead of the loading and setting the Markdown, I was hoping that it could navigate relative paths directly, but it doesn't seem to work for me.

whistyun commented 11 months ago

MdXaml v1.22.0 adds a new property MarkdownScrollViewer.Fragment. The Fragment property moves the scroll to the anchor of the current page.

// MarkdownScrollViewer mdview;
mdview.Fragment= "#list";

This version also supports uri with fragment in MarkdownScrollViewer.Source property. It navigates other or same markdown reource and scroll to the anchor.

// MarkdownScrollViewer mdview;
mdview.Source= @"https://raw.githubusercontent.com/whistyun/MdXaml/master/samples/MdXaml.Demo/MainWindow.md#list";
//  or
mdview.Source= @"file:///D:\MdXaml\samples\MdXaml.Demo\MainWindow.md#list";