Navigating to a specific fragment in a flow document from code behind - c#

I have a WPF page used as an input form which contains a number of controls on one side, and a flow document reader on the other.
I want to set the content of this document reader to a specific part of a flow document which is loaded when the form is loaded, (via a loaded event).
I have found an article explaining how to do this, using fragments, but the examples shown are only expressed in XAML.
In my case I need to update the document property of the flow document reader when the user gives focus to one the controls (I have wired up the events already) therefore I need to do this in the code behind rather than XAML.
I have tried setting the document property to:
Document#Control_Sport
where Document is the name of XAML flow document and Control_Sport is the name of the fragment I need to navigate to.
However this gives an error, it doesn't like the hash sign being there.
I tried looking on MSDN but its XAML only. Is there a way I can do this through code?
Any help would be appreciated.
Felix,
Link to MSDN article: http://msdn.microsoft.com/en-us/library/ms750478.aspx#FragmentNavigation

You can navigate to any Block within a FlowDocument by calling Block.BringIntoView.

First, create a Frame object inside your Page or Window object. Setting the JournalOwnership property to "OwnsJournal" will give the document its own navigation bar (forward and back arrows plus a history). You will probably need to add additional parameters to size and locate the frame within your document as well, but I didn't include them in my example since I don't know what your app requires:
<Frame Name="MyFrame" JournalOwnership="OwnsJournal" />
Then, create a pack URI for your document fragment. This document is assumed to be in the same directory as the application's executable; you will need to add more to the path to navigate to the directory where the document resides in your project:
Uri MyUri = new Uri("pack://application:,,,/MyXamlDocument.xaml#MyFragment");
Then, navigate to it from inside your button's Click handler or whatever other means you like to initiate the navigation:
MyFrame.Navigate(MyUri);

Related

How to execute script using webview2 to expand an html element using c#

I'm not quite sure how to ask this question. So I'm attaching two images
How can I expand the Product Details tab so that the html rendered in the webview2 control looks like the second picture using code behind?
You can inject script into a page using CoreWebView2.ExecuteScriptAsync that will find that element and perform a click on it. However, this will be a fragile solution since if the layout of the page or names of elements on the page change your script may no longer work.
I would recommend opening the desired page in the Edge browser, opening DevTools, Console, and trying out different script to click on the correct element. For example document.getElementById("product-section-overview").children[0].children[0].click() might work but depends on the ID of that element not changing, and the structure and order of its children.
Once you have the script you want you can inject it into the document via
await myWebView2.CoreWebView2.ExecuteScriptAsync("document.getElementById("product-section-overview").children[0].children[0].click()");
If you are interested in a library for use with WebView2 that provides a DOM API and automation functionality then you can try WebView2.DevTools.Dom. It's free for anyone to use.
// Add using WebView2.DevTools.Dom; to access the CreateDevToolsContextAsync extension method
// Only a single WebView2DevToolsContext should exist at any given time, when you are finished them make sure you dispose via DisposeAsync. The WebView2DevToolsContext can be reused if required
await using var devToolsContext = await webView.CoreWebView2.CreateDevToolsContextAsync();
// Get element by Id
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var element = await devToolsContext.QuerySelectorAsync<HtmlElement>("#myElementId");
// Click The element
// This will simulate a mouse move then click
await element.ClickAsync();
More details and examples in the Readme

How can I insert an element to the bottom of a specific page in iText7?

I'm exploring different options for .NET PDF libraries. One of my requirements is to place a box at the bottom of the first page and if any of the content reaches the box, it should overflow onto the next page.
For example:
Shown above, paragraph 7 would normally take up some of the space that's occupied by the "reserved" area. Instead, the part that would have taken up that space is shifted to the next page.
That image was achieved using Gembox.Document by adding the box as a footer element that only renders on the first page. However, in iText7, the examples I've seen for adding a footer (such as this one), places the content as a floating element that renders over the existing content and does not affect the layout/flow of the rest of the document.
I also tried adding a paragraph on the PageEnd event handler without the canvas (snippet below), but instead of adding it to the specified page, it's added to the end of the entire document.
public void HandleEvent(Event evt)
{
var docEvent = (PdfDocumentEvent)evt;
var page = docEvent.GetPage();
int pageNum = docEvent.GetDocument().GetPageNumber(page);
if (pageNum == 1)
{
doc.Add(new Paragraph("Testing a thing"));
}
}
Is the type of effect I'm looking for something that I can replicate using iText7?
I believe you can combine the concepts of https://github.com/itext/i7ns-samples/blob/develop/itext/itext.samples/itext/samples/sandbox/acroforms/AddExtraTable.cs and https://github.com/itext/i7ns-samples/blob/develop/itext/itext.samples/itext/samples/sandbox/events/TextFooter.cs to achieve what you need.
The idea is as follows:
reserve place for your box by making iText give the document's renderer less space for the first page
fill this box with a help of iText's end page events
Another option was suggested in How can I insert an element to the bottom of a specific page in iText7? : you can temporary call Document#setBottomMargin , since elements added via Document#add will not be placed on margins. Then, once the first page is layouted, you can set the initial margins again. This option, however, requires understanding of you layout flow, since the margins should be set only after the content of the first page is layouted.
One more suggestion: althouth event functionality is rather flexible and useful, it seems like using a sledgehammer to crack a nut. You need to call Canvas#ShowTextAligned, which could be done without any event handling. So ideally I would prefer to do the following:
handle page's layout area via an extension of DocumentRenderer
Calling Canvas#ShowTextAligned to fill the reserved box.
As you said, you are exploring different .NET PDF libraries. So I would advise PDFFlow library, which does exactly what you need.
If you have a footer, main document flow will take the rest of page area and will be automatically continued at the next page without overlaying footer.
DocumentBuilder.New()
.AddSection()
.AddParagraph("long text")
.ToSection()
.AddFooterToBothPages(40)
.AddParagraph("this a footer set for each page of this section")
.ToDocument()
.Build("result.pdf");
Here is a tutorial with code examples of using headers, footers, left/right repeating areas: AddingRepeatingArea tutorial.
Hope, this will help you :)

How can I separate the navigation of an XpsDocument in a DocumentViewer control from the containing NavigationWindow?

In some WPF XAML, I'm using a DocumentViewer control within my NavigationWindow to display an XPS document (via the XpsDocument class), per the simple instructions here on the MSDN Blogs.
Unfortunately, the navigation within the XPS document (internal hyperlinks) propagate to the journal of the NavigationWindow, rather than being contained within the DocumentViewer control. I'm wondering how I can separate the two, perhaps using a Frame that points to some XAML that contains the DocumentViewer, per the topic pictured here on MSDN. But I'm really new to this whole idea. Does anyone have or know of any code they could point me toward?
Thanks in advance!
I figured this out by piecing together documentation and information from MSDN. Some code fragments below in case it helps anyone else.
Within the UserControl navigated to by the NavigationWindow I placed (among other window content) the Frame, as shown
<Frame Name="xpsFrame" NavigationUIVisibility="Hidden" JournalOwnership="OwnsJournal" />
and in the code behind I called
XpsDocument xpsDoc = new XpsDocument(pathToDocument, System.IO.FileAccess.Read);
manualFrame.Navigate(xpsDoc.GetFixedDocumentSequence());
This allowed the display of the XPS document within a specified portion of the NavigationWindow while keeping the navigation within the XPS document (in the Frame) separate from the main window navigation.

Embedded WebBrowser in Windows Form C# project

I have a form with an embedded web browser control on it. I am currently using WebBrowser and use it like so:
webBrowser1.Navigate("about:blank");
HtmlDocument doc = this.webBrowser1.Document;
doc.Write(string.Empty);
String htmlContent = GetHTML();
doc.Write(htmlContent);
This writes the HTML correctly to the web browser control BUT it never clears the existing data and it just appends, so I end up with N web pages stacked on top of each other.
Is this the best control to use? If so why is it not clearing existing data?
You need to use:
HtmlDocument doc = this.webBrowser1.Document.OpenNew(true);
now the contents of the document will be cleared before writing.
All calls to Write should be preceded
by a call to OpenNew, which will clear
the current document and all of its
variables. Your calls to Write will
create a new HTML document in its
place. To change only a specific
portion of the document, obtain the
appropriate HtmlElement and set its
InnerHtml property.
Yes, it is.
You should be able to call the Clear method if you need to clear contents.
Check this article for in-depth details and sample code:
http://www.codeproject.com/KB/miscctrl/simplebrowserformfc.aspx
Call HtmlDocument.OpenNew between pages:
OpenNew will clear the previous loaded
document, including any associated
state, such as variables. It will not
cause navigation events in WebBrowser
to be raised.

c# webbrowser control displaying "special folder" contents : why are Document and DocumentDom always null?

In a C# WinForms, .NET Framework 3.5, project with a WebBrower control on the form :
... with a project reference set to MSHTMLdll and the WinForm code : "using mshtml;" ...
you can load a "special folder," like the Favorites folder, into the browser easily.
after you've loaded a "special folder" : what appears in the WebBrowser is essentially a kind of "explorer" view : you have the choice of typical "explorer" view-styles of 'Details, etc. in Details view you have a row-column matrix, with typical "Explorer" style column heads, etc.
Normally I would "get at" the DOM of the WebBrowser via casting the Document, or the DomDocument of the Document, to the IHTMLDocument2 interface exposed by mshtml.dll :
IHTMLDocument2 HTMLDocument = (IHTMLDocument2)webBrowser1.Document;
// also tried this
// IHTMLDocument2 HTMLDocument = (IHTMLDocument2)webBrowser1.Document.DomDocument;
// also tried this
// HTMLDocumentClass HTMLDocument = webBrowser1.Document.DomDocument as HTMLDocumentClass;
But in this case, viewing a "special folder" contents, I'm always getting the Document as null.
It is interesting that you can while viewing a special folder, like the Favorites, create a new folder and do other "file ops" : I wonder if I am "getting away with this" because I have protected mode turned off on IE8 ?
Appreciate any ideas about how to access the DOM while viewing special folder in the WebBrowser controls.
thanks ! Bill
The folder view isn't HTML document, so you can not use HTML interface to access the content. Use shell interfaces like IShellBrowser, IShellView and IFolderView if you are really interested in what's displayed in the window.
Typically the webbrowser's document property will be null until a page is loaded. You can try this to initialize the document property:
webBrowser1.Navigate("about:blank");
while (webBrowser1.Document.Body == null) Application.DoEvents();
// now you can access the Document property, including getting/setting the innerHtml
However, I'm not sure this will help you since the fact that the Document property is null, while you are still viewing what you want to see, suggests that even when the Document property is no longer null, that will not be the way to access the special folder data. But you can try the above code, then loading your special folder, and then looking at the document and see what you get...

Categories