IWebBrowser2 IHTMLDocument2 CTRL+F dialog appears but finds no matches - iwebbrowser2

I'm generating HTML pages from strings stored in a database by using the IHTMLDocument2 write(SAFEARRAY) method. This works OK.
When CTRL+F is pressed the Find dialog appears as expected, but there are never any matches. What is being searched by CTRL+F? Perhaps an object is missing(that I must create) that the search looks at?
Here's some relevant code:
CComPtr<IDispatch> m_spDisp;
CComPtr<IWebBrowser2> m_spWeb2;
HRESULT m_hr;
IHTMLDocument2* m_document;
BOOL CSwiftDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_BackMenuButton.SetToolTipText(_T("Back"));
m_bInitialised = true;
m_bBackClicked = false;
m_svURLList.clear();
m_nCurrentPage = -1;
m_bitBack.LoadBitmap(IDB_BACK_BITMAP);
m_BackMenuButton.SetBitmap(m_bitBack);
m_spGlobal.CreateInstance(__uuidof(GLOBVARSLib::Global ) );
m_browser.Navigate(CSTR m_sURL, NULL, NULL, NULL, NULL);
GetDocument();
WriteHTMLString();
SetWindowSize(512,384);
return TRUE;
}
void CSwiftDlg::GetDocument()
{
m_hr = S_OK;
m_spDisp = m_browser.get_Application();
if (m_spDisp != NULL && m_spWeb2 ==NULL)
{
m_hr = m_spDisp->QueryInterface(IID_IWebBrowser2,(void**)&m_spWeb2);
}
if (SUCCEEDED(m_hr) && m_spWeb2 != NULL)
{
// get browser document's dispatch interface
IDispatch *document_dispatch = NULL;
m_hr = m_spWeb2->get_Document(&document_dispatch);
if (SUCCEEDED(m_hr) && (document_dispatch != NULL))
{ // get the actual document interface
m_hr = document_dispatch->QueryInterface(IID_IHTMLDocument2, (void **)&m_document);
// release dispatch interface
document_dispatch->Release();
}
}
}
void CSwiftDlg::WriteHTMLString()
{
if (m_document == NULL)
GetDocument();
SAFEARRAY *empty_array = SafeArrayCreateVector(VT_VARIANT,0,1);
// construct text to be written to browser as SAFEARRAY
SAFEARRAY *safe_array = SafeArrayCreateVector(VT_VARIANT,0,1);
VARIANT *variant;
SafeArrayAccessData(safe_array,(LPVOID *)&variant);
variant->vt = VT_BSTR;
variant->bstrVal = m_sHTML.AllocSysString();
SafeArrayUnaccessData(safe_array);
// write SAFEARRAY to browser document
m_document->write(empty_array);
m_document->close();
m_document->write(safe_array);
}
Answer:
As #Yahia suggested, it was a focus problem. I added m_document->execCommand("Refresh",...) after the m_document->write(safe_array) statement, as when I did "refresh" from the context menu Ctrl-F worked as expected. That fixed the "focus issue".

CTRL+F is focus-aware... you need to call focus on the parentWindow of m_document after WriteHTMLString(); and/or SetWindowSize(512,384);...

Related

Get first visible item in a GridView/ListView

I'm showing a set of pictures in a page. I use a GridView to show the pictures. However, when the user resizes the screen to make it narrow, I switch to a ListView.
The problem now is synchronizing the scroll position for the two lists. My approach to the solution is,
1. Get the first visible item of the first list.
2. Scroll the second list to that item using ScrollIntoView
However I'm unable to see any property in GridView/ListView that gives me the first information. Any ideas?
Also any other ways of doing this are appreciated.
That seems to be just about the way I would first try to do it. You can use the ItemsPanelRoot property of the GridView/ListView and get the Children of the panel, then use TransformToVisual().TransformPoint() relative to the list control on each child to find the first one that is visible.
The one gotcha I can think of is when ScrollIntoView() would scroll the item that was first in view port in one list to show as last in view in the other one. Maybe you could get the ScrollViewer from the template of the list control (e.g. by using VisualTreeHelper) and scroll to the beginning of the list first?
The most simple way to do it all might be to just scroll to the same relative offset in the list coming into view as the one going out. It might not be very precise, but it could work.
You could even do a nice animated transition of elements in one list into the elements in the other one.
*Update
I asked around and it seems like I forgot that the default panels in GridView and ListView - the ItemsWrapGrid and ItemsStackPanel contain a FirstVisibleIndex property that could be used to get the object and then call ScrollIntoView() on the list control, which in turns takes a ScrollIntoViewAlignment enum you can use to say you want the scrolled-to-item to be the first visible (aligned to the leading edge).
*Update 2
For ListViewBase - you can also use the ListViewPersistenceHelper to get and set relative offsets.
This upcoming update to WinRT XAML Toolkit might be helpful as it would allow you to simply call: gridView.SynchronizeScrollOffset(listView); or vice versa.
public static class ItemsControlExtensions
{
public static ScrollViewer GetScrollViewer(this ItemsControl itemsControl)
{
return itemsControl.GetFirstDescendantOfType<ScrollViewer>();
}
public static int GetFirstVisibleIndex(this ItemsControl itemsControl)
{
// First checking if no items source or an empty one is used
if (itemsControl.ItemsSource == null)
{
return -1;
}
var enumItemsSource = itemsControl.ItemsSource as IEnumerable;
if (enumItemsSource != null && !enumItemsSource.GetEnumerator().MoveNext())
{
return -1;
}
// Check if a modern panel is used as an items panel
var sourcePanel = itemsControl.ItemsPanelRoot;
if (sourcePanel == null)
{
throw new InvalidOperationException("Can't get first visible index from an ItemsControl with no ItemsPanel.");
}
var isp = sourcePanel as ItemsStackPanel;
if (isp != null)
{
return isp.FirstVisibleIndex;
}
var iwg = sourcePanel as ItemsWrapGrid;
if (iwg != null)
{
return iwg.FirstVisibleIndex;
}
// Check containers for first one in view
if (sourcePanel.Children.Count == 0)
{
return -1;
}
if (itemsControl.ActualWidth == 0)
{
throw new InvalidOperationException("Can't get first visible index from an ItemsControl that is not loaded or has zero size.");
}
for (int i = 0; i < sourcePanel.Children.Count; i++)
{
var container = (FrameworkElement)sourcePanel.Children[i];
var bounds = container.TransformToVisual(itemsControl).TransformBounds(new Rect(0, 0, container.ActualWidth, container.ActualHeight));
if (bounds.Left < itemsControl.ActualWidth &&
bounds.Top < itemsControl.ActualHeight &&
bounds.Right > 0 &&
bounds.Bottom > 0)
{
return itemsControl.IndexFromContainer(container);
}
}
throw new InvalidOperationException();
}
public static void SynchronizeScrollOffset(this ItemsControl targetItemsControl, ItemsControl sourceItemsControl, bool throwOnFail = false)
{
var firstVisibleIndex = sourceItemsControl.GetFirstVisibleIndex();
if (firstVisibleIndex == -1)
{
if (throwOnFail)
{
throw new InvalidOperationException();
}
return;
}
var targetListBox = targetItemsControl as ListBox;
if (targetListBox != null)
{
targetListBox.ScrollIntoView(sourceItemsControl.IndexFromContainer(sourceItemsControl.ContainerFromIndex(firstVisibleIndex)));
return;
}
var targetListViewBase = targetItemsControl as ListViewBase;
if (targetListViewBase != null)
{
targetListViewBase.ScrollIntoView(sourceItemsControl.IndexFromContainer(sourceItemsControl.ContainerFromIndex(firstVisibleIndex)), ScrollIntoViewAlignment.Leading);
return;
}
var scrollViewer = targetItemsControl.GetScrollViewer();
if (scrollViewer != null)
{
var container = (FrameworkElement) targetItemsControl.ContainerFromIndex(firstVisibleIndex);
var position = container.TransformToVisual(scrollViewer).TransformPoint(new Point());
scrollViewer.ChangeView(scrollViewer.HorizontalOffset + position.X, scrollViewer.VerticalOffset + position.Y, null);
}
}
}

Auto manage and protect Created\Updated fields with Entity Framework 5

I want so every added\changed record will have a time stamp of creation\change.
But - so it will be easy to embed and easy to manage - automatically.
Overwrite the 'DbContext' class or embed this in the '.tt' file (Codefirst \ DBFirst)
The code assume so you have the fields 'CreatedOn'\'ModifiedOn' inside the POCO.
If you don't have them, or you have only one - the code will work fine.
Be aware! If you use a extension (as this one) so allow you to do batch updates or changes from a stored procedure - this will not work
EDIT:
I found the source of my inspiration - thanks 'Nick' here
public override int SaveChanges()
{
var context = ((IObjectContextAdapter)this).ObjectContext;
var currentTime = DateTime.Now;
var objectStateEntries = from v in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where v.IsRelationship == false && v.Entity != null
select v;
foreach (var entry in objectStateEntries)
{
var createdOnProp = entry.Entity.GetType().GetProperty("CreatedOn");
if (createdOnProp != null)
{
if (entry.State == EntityState.Added)
{
if (createdOnProp != null)
{
createdOnProp.SetValue(entry.Entity, currentTime);
}
}
else
{
Entry(entry.Entity).Property("CreatedOn").IsModified = false;
}
}
var modifiedOnProp = entry.Entity.GetType().GetProperty("ModifiedOn");
if (modifiedOnProp != null)
{
modifiedOnProp.SetValue(entry.Entity, currentTime);
}
}
return base.SaveChanges();
}

Unable to use drag Drop in radtreeview

I have binded all data to RadTreeView but unable to use drag-'n-drop. I used four properties as
IsDragDropEnabled="True"
IsDropPreviewLineEnabled="True"
AllowDrop="True"
IsDragPreviewEnabled="True"
and I want to drop an item within same tree. But it doesnt work.
There is quite a bit of info here : http://www.telerik.com/help/silverlight/raddraganddrop-events.html
But I'm also having trouble with the tree view.
After a quick read of this telerik article, drag-drop seems to be working quite well for me.
<telerik:RadTreeView ... EnableDragAndDrop="true" OnNodeDrop="MyTreeView_NodeDrop">
EnableDragAndDrop and OnNodeDrop seem to be the two vital pieces to getting it working, but weren't in your list of attributes you tried. HTH
<telerik:RadTreeView x:Name="treeView1" IsDragDropEnabled="True" Margin="2,0,0,0" ItemsSource="{Binding SelectedSectionList, Mode=TwoWay}" ItemTemplate="{StaticResource SectionTemplate}" IsEditable="True" SelectedItem="{Binding SelectedCustomSectionList, Mode=TwoWay}" Grid.Column="2">
Now in the code behind
You have to fire event
In Constructor
this.treeView1.AddHandler(RadDragAndDropManager.DropQueryEvent, new EventHandler<DragDropQueryEventArgs>(OnDropQuery), true);
Then
private void OnDropQuery(object sender, DragDropQueryEventArgs e)
{
RadTreeViewItem destinationItem = e.Options.Destination as RadTreeViewItem;
object source = this.GetItemFromPayload<object>(e.Options.Payload);
object target = destinationItem != null ? destinationItem.Item : null;
DropPosition position = destinationItem != null ? destinationItem.DropPosition : DropPosition.Inside;
if (source != null && target != null)
{
Section sourceSection = source as Section;
Section targetSection = target as Section;
Question sourceQuestion = source as Question;
Question targetQuestion = target as Question;
if (sourceQuestion != null)
{
try
{
if (sourceQuestion != null && targetQuestion != null && object.ReferenceEquals(sourceQuestion, targetQuestion))
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
if (targetQuestion != null && position == DropPosition.Inside)
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
if (position != DropPosition.Inside && targetQuestion == null)
{
sourceSection.Questions.Remove(sourceQuestion);
targetSection.Questions.Add(sourceQuestion);
e.QueryResult = false;
return;
}
}
catch (Exception ex)
{
}
}
}
else
{
e.QueryResult = false;
return;
}
e.QueryResult = true;
}
This is it. You will be able to drag and drop.

Permutation of Actionscript 3 Array

Greetings,
This is my first post and I hope someone out there can help. I am an educator and I designed a quiz using Actionscript 3 (Adobe Flash) that is to determine all the different ways a family can have three children.
I have two buttons that enter either the letter B (for boy) or G (for girl) into an input text field named text_entry. I then have a submit button named enter_btn that checks to see if the entry into the input text is correct. If the input is correct, the timeline moves to the next problem (frame labeled checkmark); if it is incorrect the timeline moves to the end of the quiz (frame 62).
The following code works well for any particular correct single entry (ie: BGB). I need to write code in which all eight correct variations must be entered, but they can be entered in any order (permutation):
ie:
BBB,BBG,BGB,BGG,GBB,GBG,GGB,GGG; or
BGB,GGG,BBG,BBB,GGB,BGB,GGB,BGG; or
GGB,GGG,BBG,BBB,GGB,BGB,BGB,BGG; etc...
there are over 40,000 ways to enter these eight ways of having three children. Help!
baby_B.addEventListener(MouseEvent.CLICK, letterB);
function letterB(event:MouseEvent)
{
text_entry.appendText("B");
}
baby_G.addEventListener(MouseEvent.CLICK, letterG);
function letterG(event:MouseEvent)
{
text_entry.appendText("G");
}
enter_btn.addEventListener(MouseEvent.CLICK, check);
function check(event:MouseEvent):void {
var solution_S:Array=["BBB","BBG","BGB","BGG","GBB","GBG","GGB","GGG "];
if(solution_S.indexOf(text_entry.text)>=0)
{
gotoAndStop("checkmark");
}
else
{
gotoAndPlay(62);
}
}
If you know the correct code, please write it out for me. Thanks!
You will just need to keep a little bit of state to know what the user has entered so far. One possible way of doing that is to have a custom object/dictionary that you initialize outside all your functions, so that it is preserved during the transitions between frames/runs of the functions:
var solutionEntered:Object = {"BBB":false, "BBG":false, /*fill in rest */ };
Then in your function check you can perform an additional check, something like:
function check(event:MouseEvent):void {
var solution_S:Array=["BBB","BBG","BGB","BGG","GBB","GBG","GGB","GGG "];
if(solution_S.indexOf(text_entry.text)>=0) {
// We know the user entered a valid solution, let's check if
// then entered it before
if(solutionEntered[text_entry.text]) {
// yes they entered it before, do whatever you need to do
} else {
// no they haven't entered it, set the status as entered
solutionEntered[text_entry.text] = true;
}
// continue rest of your function
}
// continue the rest of your function
}
Note that this is not necessarily an optimal solution, but it keeps with the code style you already have.
Try this:
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.display.Sprite;
var correctAnswers : Array = [ "BBB", "BBG", "BGB", "GBB", "BGG", "GGB", "GBG", "GGG" ];
var answersSoFar : Array;
var textField : TextField; //on stage
var submitButton : Sprite; //on stage
var correctAnswerCount : int;
//for testing
textField.text = "BBB,BBG,BGB,GBB,BGG,GGB,GBG,GGG";
//textField.text = "BGB,BBB,GGG,BBG,GBB,BGG,GGB,GBG,";
//textField.text = "BBB,BBG, BGB,GBB,BGG, GGB, GBG, GGG";
//textField.text = "BBB,BBG,BGB,GBB,BGG,GGB,GBG";
//textField.text = "BBB,BBG,BGB,GBB,BGG,GGB,GBG,GGG,BBG";
submitButton.addEventListener( MouseEvent.CLICK, onSubmit );
function onSubmit( event : MouseEvent ) : void
{
var answers : Array = getAnswersArray( textField.text );
answersSoFar = [];
correctAnswerCount = 0;
for each ( var answer : String in answers )
if ( answerIsCorrect( answer ) ) correctAnswerCount++;
if ( correctAnswerCount == correctAnswers.length ) trace( "correct" );
else trace( "incorrect" );
}
function getAnswersArray( string : String ) : Array
{
string = removeInvalidCharacters( string );
return string.split( "," );
}
function removeInvalidCharacters( string : String ) : String
{
var result : String = "";
for ( var i : int, len = string.length; i < len; i++ )
if ( string.charAt( i ) == "B" || string.charAt( i ) == "G" || string.charAt( i ) == "," )
result += string.charAt( i );
return result;
}
function answerIsCorrect( answer : String ) : Boolean
{
if ( answerIsADuplicate( answer ) ) return false;
else answersSoFar.push( answer );
if ( answerIsInListOfCorrectAnswers( answer ) ) return true;
return false;
}
function answerIsInListOfCorrectAnswers( answer : String ) : Boolean
{
if ( correctAnswers.indexOf( answer ) == -1 ) return false;
return true;
}
function answerIsADuplicate( answer : String ) : Boolean
{
if ( answersSoFar.indexOf( answer ) == -1 ) return false;
return true;
}
note that in the original code you pasted, you have an extra space in the last element of your correct answer list - "GGG " should be "GGG"
this works
baby_B.addEventListener(MouseEvent.CLICK, letterB);
function letterB(event:MouseEvent) {
text_entry.appendText("B");
}
baby_G.addEventListener(MouseEvent.CLICK, letterG);
function letterG(event:MouseEvent) {
text_entry.appendText("G");
}
var valid:Array = ["BBB","BBG","BGB","BGG","GBB","GBG","GGB","GGG"];
enter_btn.addEventListener(MouseEvent.CLICK, check);
function check(event:MouseEvent):void {
var parts:Array = text_entry.text.split(/,\s*/g); // split the text into component parts
var dup:Array = valid.slice(); // copy the correct list
while(parts.length){ // run through each answer component
var part:String = parts.pop(); // grab the last one
part = part.replace(/(^\s+|\s+$)/g, ''); // strip leading/trailing white space
var pos:int = dup.indexOf(part); // is it in the list of correct answers?
if(pos != -1){ // if it is...
dup.splice(pos, 1); // then remove that answer from the list
}
}
if(dup.length == 0) { // if it's 0, they got all the correct answers
gotoAndStop("checkmark");
} else { // otherwise, they didn't get one or more correct answers
gotoAndPlay(62);
}
}

Getting Web page document in Windows mobile 6.0

After searching lot on the internet we have found following code to get only body part of the web page loaded onto web browser control
IPIEHTMLDocument2 *pHTMLDocument;
IPIEHTMLElement* pBodyElement;
CComPtr<IDispatch> spDispDoc;
HRESULT res = m_spWebBrowser2->get_Document(&spDispDoc);
if(SUCCEEDED(res))
{
spDispDoc->QueryInterface( __uuidof(IPIEHTMLDocument2), (void**)&pHTMLDocument);
WCHAR szText[256];
DISPID id;
OLECHAR FAR* szTemp;
// store "body"
szTemp = szText;
StringCchPrintf(szText, 256, L"body", id);
// get the body
pHTMLDocument->GetIDsOfNames(IID_NULL, &szTemp, 1, LOCALE_USER_DEFAULT, &id);
VARIANT varResult;
varResult.vt = VT_DISPATCH;
VARIANT FAR *pVarResult = &varResult;
DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
pHTMLDocument->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, pVarResult, NULL, NULL);
BSTR bodyValue;
if( NULL != pVarResult->pdispVal)
{
pVarResult->pdispVal->QueryInterface(IID_IPIEHTMLElement, (void**)&pBodyElement);
pBodyElement->get_innerHTML(&bodyValue);
}
}
But now how we get the remaining head and other tag document text from the loaded web page,
even we have tried passing "head" string to the GetIDsOfNames() method and it passes fail value, so we are struck.
Please provide us the method to access/ extract entire web page content in windows mobile 6.0
Thanks,
Ramanand Bhat.
void CBrowserWindow::ExtractWebPageDoc()
{
HRESULT hrResult = E_FAIL;
IDispatch *pIDisp = NULL;
IPIEHTMLDocument3 *pIHTMLDocument = NULL;
IPIEHTMLElementCollection *pHTMLElementcol = NULL;
IPIEHTMLImgElement *pHTMLImgElement = NULL;
hrResult = m_spIWebBrowser2->get_Document( &pIDisp);
if (NULL != pIDisp)
{
hrResult = pIDisp->QueryInterface( __uuidof(IPIEHTMLDocument3), (void**)&pIHTMLDocument);
if( NULL != pIHTMLDocument)
{
IPIEHTMLElement* pElement = NULL;
CComBSTR pHTMLElement;
hrResult = pIHTMLDocument->get_documentElement( &pElement);
if (SUCCEEDED(hrResult))
{
pElement->get_innerHTML(&pHTMLElement.m_str);
SaveToHTMLFile( pHTMLElement);
}
hrResult = pIHTMLDocument->get_images( &pHTMLElementcol);
if (NULL != pHTMLElementcol)
{
CComBSTR strImage;
VARIANT vtBase, vtIndex;
long pHTMLElementCollectionLength = 0;
VariantInit( &vtBase);
vtIndex.vt = VT_UINT;
hrResult = pHTMLElementcol->get_length( &pHTMLElementCollectionLength);
for (int ilen = 0; ilen < (int)pHTMLElementCollectionLength ; ilen++)
{
vtIndex.lVal = ilen;
pIDisp = NULL;
hrResult = pHTMLElementcol->item( vtBase, vtIndex , &pIDisp);
if (NULL != pIDisp)
{
hrResult = pIDisp->QueryInterface( __uuidof(IPIEHTMLImgElement), (void**)&pHTMLImgElement);
if (NULL != pHTMLImgElement)
//CComQIPtr<IPIEHTMLImgElement> imgElement( pIDisp);
//imgElement->get_src( &strImage.m_str); //I get it here :)
pHTMLImgElement->get_src( &strImage.m_str);
}
}
}
}
}
}
Above mentioned code gets the entire web page content in windows mobile devices.