.NET WPF WebBrowser Control: Insert HTML at ControlRange selection - c#

I have a WebBrowser control that I am using to create an HTML editor, and I need to be able to insert a string of HTML at the current selection in the document.
Generally, I can do something like this to paste HTML at the current selection, if the selection is a text selection:
IHTMLSelectionObject selection = webBrowser.Document.DomDocument.selection;
// Assume that selection.type == "Text"
IHTMLTxtRange textRange = selection.createRange() as IHTMLTxtRange;
textRange.pasteHTML(myHtmlString);
However, if the current selection is a ControlRange selection, there doesn't seem to be any direct way to insert/paste HTML at that position.
For example:
// Assume that selection.type == "Control"
IHTMLControlRange ctrlRange = selection.createRange() as IHTMLControlRange;
// This throws an error, as IHTMLControlRange has no pasteHTML method
ctrlRange.pasteHTML(myHtmlString);
I know that I can use the HtmlElement.InsertAdjacentElement method to insert an element before or after another element, but that is very limiting, as sometimes I need to be able to insert raw HTML, rather than needing to create an HtmlElement object for it first.
Is there any way to be able to paste/insert an HTML string at the caret position, or over a ControlRange selection?

I have found a workaround for this problem, at least for my specific use case.
The IHTMLSelectionObject.createRange() method returns dynamic, but it will resolve to either an IHTMLTxtRange or an IHTMLControlRange, depending on what the selection type is.
If selection.type == "Text" or selection.type == "None", it returns an IHTMLTxtRange, and if selection.type == "Control", it returns an IHTMLControlRange.
The following statement works for empty selections and text selections:
DomDocument.selection.createRange().pasteHTML(myHtml);
However, in the case of pasting over a control selection, the above statement won't work by default because the createRange() method will return an IHTMLControlRange, which, as mentioned above, has no createRange() method. However, we would be wanting to overwrite the current selection with the new HTML anyway, so one could assume that it is safe to just clear the selection (delete it) and then paste the HTML at the newly empty selection.
Solution
Something like this should work for all types of selections:
// If we have a control selection, clear the selection
if (DomDocument.selection.type == "Control")
DomDocument.selection.clear();
// Now it is no longer a control selection, but an empty text selection
DomDocument.selection.createRange().pasteHTML(myHtml);
This does feel a bit hacky, but it solves the problem for me.

Related

UltraGrid Filter cell property

Working on a code that was written by someone else. Here are the important parts of the code:
UltraGridColumn col = columns.Add("FolderImage", "Status");
col.Header.Fixed = true;
col.AllowRowFiltering = Infragistics.Win.DefaultableBoolean.False;
There is more code written to specify the behavior of the folder, but it is irrelevant for the example; As of right now, the following result is generated:
As you can see, there is a greyed out "Filter" button, and the pin is missing:
I want it to look like this:
I.e. filter button needs to go in the status column (it just needs to be blank), and the pin button should be enabled. According to the Infragistics manual, the code above should produce the very results I am looking for, but it does not.
To hide the filter operator (the 'A' letter) you need to set FilterOperatorLocation of the column to Hidden. To show the pin of the fixed column you need to set to its header FixedHeaderIndicator to Button (by the way this is default value, so if you did not override it at some other place you may skip this step). Try to use code like this:
col.FilterOperatorLocation = FilterOperatorLocation.Hidden;
col.Header.FixedHeaderIndicator = FixedHeaderIndicator.Button;
For the "A" button in a cell, the following code fixed it:
col.FilterOperatorLocation = FilterOperatorLocation.Hidden;
For the pin, I had to enable the "UsedFixedHeaders" property:
this.gridName.DisplayLayout.UseFixedHeaders = true;

VSTO Word Add-in - insert Content Control around selected text

I'm trying to add a rich text content control around the user's selected text in a Word document.
I'm new to VSTO and Content Controls so i'm using the MSDN examples as a baseline. The example shows this, which adds the Content Control at the chosen position:
private void AddRichTextControlAtSelection()
{
word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;
currentDocument.Paragraphs[1].Range.InsertParagraphBefore();
currentDocument.Paragraphs[1].Range.Select();
Document extendedDocument = Globals.Factory.GetVstoObject(currentDocument);
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl("richTextControl1");
richTextControl1.PlaceholderText = "Enter your first name";
}
However i want the Content Control to wrap around the user's selected text. Any help, please?
What you found is one possibility. More efficient and "cleaner" (IMO) would be to use the constructor that accepts a RANGE object and pass the Range. If you want the user's selection then
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl(extendedDocument.Parent.Selection.Range, "richTextControl1");
//the Parent of a Document is the Word.Application
//Selection is a dependent of the Word.Application
Otherwise, building on your code sample:
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl(currentDocument.Paragraphs[1].Range, "richTextControl1");
Note that if you don't need to work with VSTO's extensions of the Content Controls you don't need to go through the GlobalFactory steps, you can simply insert the "interop" versions of the Content Controls.
Simple fix in the end: currentDocument.ActiveWindow.Selection.Range.Select();

Watin Visible of Text

I'm Using Watin tool in C# to find a text is available in webpage/URL. Using the code:
bool flag = browser.containsText("Some Text");
But returns true, but the text("Some Text") is hidden in page. I need to get only visible text of a URL. i Dont Have the ID/Name of the Element...
Find the control that is hidden and check to see if it is visible and contains the text.
Example if it were a Div and using NUnit:
Assert.IsTrue(myBrowser.Div.Style.GetAttributeValue("visibility") == "hidden" && myBrowser.Div("myPossiblyHiddenDiv").Text.Contains("the text"));
Lots of ways to check for the text; I usually try to go as granular as possible in case there are other controls on the page that contain the text in question.

asp.net dynamically add usercontrols and position them

My issue is that I have a designer that will create a custom aspx page bu without any .net controls. I need a way of adding the controls dynamically. So far the only types of controls will be textboxes and a button, but there are 30 variations of what the textboxes can be (name, phone #, email, etc). Also the textboxes may or may not need to be required. Once the textboxes are added the form will be submitted to a db.
My first thought was to have the designer place something like [name] and then replace that with a user control that has a name textbox and a required field validator. In order to determine if the validator should be enabled I was thinking that the place holder could look like this, [name;val] or [name;noval]. I could either do replace the place holders in code dynamically or set up a tool that the user pastes their html into a textbox and clicks a button which then spits out the necessary code to create the aspx page.
I'm sure there must be a better way to do this but its a fairly unique problem so I haven't been able to find any alternatives. Does anyone have any ideas?
Thanks,
Kirk
IF your designer gives you html pages, just create a new website. copy and pages all the HTML pages with the Image folders and everything to your project. then for every HTML page create an aspx page, (with the same name) copy and pages the html's tags which are between to the aspx page's and for the body copy and paste HTML page's tags which are between into the of the aspx page.
Now you have your aspx page, exactly the same as html page.
Sounds like an attempt to over-engineer a solution to what should be a non-issue.
As #Alessandro mentioned in a comment above, why can't the designer provide you with pages that have the control markup? As it stands right now, the designer isn't providing you with "a custom aspx" so much as "a custom html page." If the designer is promising ASPX but delivering only HTML, that's a misinterpretation somewhere in the business requirements.
However, even if the designer is rightfully providing only HTML, there shouldn't be a problem with that. At worst, you can set each element you need on the server to runat="server" to access them on the server-side. Or, probably better, would be to simply replace them with the ASPX control markup for the relevant controls.
Write a simple parser that will recognize the [...] tags and replace them with corresponding controls. Its pretty easy to do and i've often done this... the tag i use is usually $$(..); though, but that doesn't matter as long as your parser knows your tags.
Such a parser will consist of a simple state-machine that can be in two states; text-mode or tag-mode. Loop through the whole page-text, char for char. As long as you're in text-mode you keep appending each char into a temporary buffer. As soon as you get into tag-mode you create a LiteralControl with the content of the temporary buffer and add it to the bottom of your Control-tree, and emtpy the buffer.
Now, you still keep adding each char into the buffer, but when you hit text-mode again, you analyze the content of the buffer and create the correct control - could be a simple switch case statement. Add the control to the bottom of your control tree and keep looping through the rest of the chars unto you read the end and keep switching back and forth between text-mode and tag-mode adding LiteralControls and concrete controls.
Simple example of such a parser... written in notepad in 4 minutes, but you should get the idea.
foreach (var c in text)
{
buffer.Append(c);
if (c== '[' && mode == Text)
{
mode = Tag;
Controls.Add(new LiteralControl(buffer));
buffer.Clear();
}
if (c == ']' && mode == Tag)
{
mode = Text;
switch (buffer)
{
case "[name]": Controls.Add(new NameControl());
... the rest of possible tags
}
buffer.Clear();
}

How can I get text under mouse pointer WebBrowser control?

I'm currently working on WYSIWYG editor using .net WebBrowser control and I need to implement spell checking.
My question is how can I get text under mouse pointer when I right click on the misspelled word to show all spell suggestions?
Tried to wrap every misspelled word in html label with javascript event, but there seems to be the problem in invoking C# code from javascript.
Ok - here are my 2 cents.
Firstly I imagine you have an editable element more than likely a div and you're using this as your WYSIWYG editor. I also guess you have an Ajax function somewhere that you've setup on a certain keystroke to check the spelling of the entire (maybe even some) of the contents of the DIV, and it can send you back a list of the misspelled words.
My idea is - 1. Create a range on the contents of your editable div, then do a search for the word using the TextRange object - here : http://msdn.microsoft.com/en-us/library/ms535872%28VS.85%29.aspx. Use the findText method which Searches for text in the document (range) and positions the start and end points of the range to encompass the search string.
Once you have this you should copy the text value into a variable, then construct a < Span> possibly even set the bottom-border style of the span to have a red underline, or even use an image so that it looks like that regular misspelled squiggly wave. Set the inner contents of this Span to the value of the original misspelled word. Also don't forget to assign an onclick (or right click) to this SPAN, so you can do another lookup on spelling suggestions later. Great, now you have an offline SPAN but its not yet inserted into the document.
Next step: Use the TextRange pasteHTML method to paste the new SPAN into the document, remember the range should already be defined from the find operation, so you shouldn't have to mess around looking for the text again (or selecting it).
Once the span is in the document using pasteHTML, it should be straight forward, just create another div, absolutely position it just under the SPAN so when the user right clicks it - the "context menu comes up" - populated by Ajax.
After that it should be a very easy case of creating another range, and replacing this time the SPAN with just straightforward text.
ALL of this is theory, but hope it helps!
Also you might want to check out - http://www.aspfree.com/c/a/Code-Examples/Searching-Body-Text-with-textRange-Enter-the-Gecko/ - which will help you make the whole solution work in FireFox (not only IE)
I'll add some more two cents in as I'm currently working on something similar.
Okay, so I'm assuming you are a WebBrowser object? If so, my suggestion would be to use a contextual menu strip every time you every time you right click. From there you can fire the context menu Opening event that will grab that specific HTML element for you.
In short you could use a similar code snippet
Point mouseLocation;
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
HtmlElement elem = webBrowser.Document.GetElementFromPoint(mouseLocation);
//From here you would do what ever it is you need for your element in the browser
}
private void webContextMenuStrip_Opening(object sender, CancelEventArgs e)
{
//This just gets you the specific mouse position for the given element
mouseLocation = webBrowser.PointToClient(MousePosition);
}
Hope this atleast gets you started and best of luck!

Categories

Resources