2016-06-17 7 views
6

Ich habe dieses sehr seltsame Problem, bei dem ein Fenster scheint, seinen Inhalt zu löschen und es nach dem Löschen nicht neu zu zeichnen. Dieser Dialog ist von CDHtmlDialog abgeleitet, was ich für einen Teil des Problems halte. Es gibt eine Art von nicht-deterministischer Codeausführung, die dazu führt, dass Code in bestimmten Fällen vor anderen ausgeführt wird und in anderen umgekehrt.Warum sollte ein Dialog seinen Inhalt löschen, ohne ihn zu aktualisieren?

Message-Handler, die beteiligt sind, sind:

BEGIN_MESSAGE_MAP(CCalcDrillDownDlg, CDHtmlDialog) 
    ON_WM_PAINT() 
END_MESSAGE_MAP() 

BEGIN_EVENTSINK_MAP(CCalcDrillDownDlg, CDHtmlDialog) 
    ON_EVENT(CCalcDrillDownDlg, AFX_IDC_BROWSER, 250 /* BeforeNavigate2 */, _OnBeforeNavigate2b, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL) 
END_EVENTSINK_MAP() 

Die OnInitDialog() Funktion ist wie folgt:

BOOL CCalcDrillDownDlg::OnInitDialog() 
{ 
    SetHostFlags(DOCHOSTUIFLAG_FLAT_SCROLLBAR); 

    CDHtmlDialog::OnInitDialog(); // << will eventually call _OnBeforeNavigate2b() 

    // Set the icon for this dialog. The framework does this automatically 
    // when the application's main window is not a dialog 
    SetIcon(m_hIcon, TRUE);   // Set big icon 
    SetIcon(m_hIcon, FALSE);  // Set small icon 

    LoadFromResource(IDR_CALC_DRILLDOWN); // << will eventually call _OnBeforeNavigate2b() 
    CString title = getStr2Ptr(22574); 
    SetWindowText(title); 
    ShowWindow(SW_SHOW); 

    return TRUE; // return TRUE unless you set the focus to a control 
} 

Dies ist die OnPaint() Funktion ist:

void CCalcDrillDownDlg::OnPaint() 
{ 
    if (IsIconic()) 
    { 
     CPaintDC dc(this); // device context for painting 

     SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 

     // Center icon in client rectangle 
     int cxIcon = GetSystemMetrics(SM_CXICON); 
     int cyIcon = GetSystemMetrics(SM_CYICON); 
     CRect rect; 
     GetClientRect(&rect); 
     int x = (rect.Width() - cxIcon + 1)/2; 
     int y = (rect.Height() - cyIcon + 1)/2; 

     // Draw the icon 
     dc.DrawIcon(x, y, m_hIcon); 
    } 
    else 
    { 
     CDHtmlDialog::OnPaint(); 
    } 
} 

ich nicht habe setzen der Inhalt der _OnBeforeNavigate2b() Funktion, wie es scheint, nicht zu ha habe etwas mit dem Neuzeichnen zu tun.

So scheint es, dass manchmal der Dialoginhalt vor dem Aufruf von CCalcDrillDownDlg::OnPaint() irgendwie gemalt wird. Wenn dies geschieht, löscht der Aufruf von CDHtmlDialog::OnPaint() den Inhalt aus dem Fenster.

Andere Zeiten, die Inhalte sind nicht auf dem Fenster vor dem Aufruf CCalcDrillDownDlg::OnPaint() gemalt. Wenn das passiert, wird der Aufruf von CDHtmlDialog::OnPaint() wahrscheinlich noch den Inhalt des Fensters löschen, das noch nicht gemalt wurde, und dann irgendwann nach dem Aufruf von CCalcDrillDownDlg::OnPaint() wird es neu gezeichnet.

Spy ++ erfasst keine Nachrichten, wenn das System das Fenster ordnungsgemäß neu erstellt, daher habe ich die von dieser Frage generierten Nachrichten entfernt.

Hat jemand eine Idee, wie das Neuzeichnen durchgeführt wird und warum die Bestellung manchmal foobarred wird?

bearbeiten

Hier ist der Inhalt der IDR_CALC_DRILLDOWN Ressource:

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <title>Calculation Drilldown</title> 
    <style type="text/css"> 
     body { overflow-y: auto; font-family: arial, Helvetica, sans-serif; font-size: 90%; } 

     a:link { color: black; } 
     a:visited { color: black; } 
     table { border-collapse: collapse; } 

     tr.runcache td { background-color: #B5B5B5; color: black; } 
     tr.runcache td a:link { color: black; } 
     tr.runcache td a:visited { color: black; } 

     tr.tracker td { background-color: white; color: black; } 
     tr.tracker td a:link { color: black; } 
     tr.tracker td a:visited { color: black; } 

     td.numericvalue { text-align: right; } 

     tr.paramTitle td { background-color: #4A4A4A; color: white; } 

     tr.resultTitle td { background-color: #4A4A4A; color: white; } 
     tr.resultTitle td a:link { color: white; } 
     tr.resultTitle td a:visited { color: white; } 

     tr.param td { background-color: white; color: black; } 
     tr.param td a:link { color: black; } 
     tr.param td a:visited { color: black; } 

     span.selection { background-color: #EBEBEB; } 
    </style> 
</head> 
<body> 
    <div id="calculation"></div> 
    <div id="details" style="padding-left: 0.1in; display: none;"></div> 
</body> 
</html> 

Edit # 2

Weitere Untersuchungen zu zeigen scheint, dass die CDHtmlDialog Klasse (oder eine Basisklasse davon) zeichnen das Fenster, unabhängig davon, ob meine CCalcDrillDownDlg::OnPaint()CDHtmlDialog::OnPaint() ruft oder nicht, was einfach komisch und nicht intuitiv ist. :(

Es scheint auch, dass dies möglicherweise threading-bezogen ist, da dies davon abhängt, wie lange es dauert, um das Fenster zu rendern. Wenn es eine kurze Zeit dauert, zeigt es fein. Wenn es eine halbe dauert Sekunde oder mehr, es vermasselt.

im Moment bin ich eine Abhilfe verwenden, wo ich eine m_bRepaint Flagge in der Klasse haben, die zunächst auf true gesetzt. nach CCalcDrillDownDlg::OnPaint() Aufruf und es ist nicht ikonischen, überprüfe ich die flag und erzwinge eine Größenänderung Dies ist nicht optimal, da es ein anfängliches Flimmern verursacht, aber es stellt zumindest sicher, dass der Inhalt des Fensters gezeichnet wird

if (!m_bRepaint) 
    { 
     CDHtmlDialog::OnPaint(); 
    } 
    else 
    { 
     CRect winRect; 
     GetWindowRect(&winRect); 
     SetWindowPos(NULL, 0, 0, winRect.Width() - 1, winRect.Height(), SWP_NOMOVE | SWP_NOZORDER); 
     SetWindowPos(NULL, 0, 0, winRect.Width() , winRect.Height(), SWP_NOMOVE | SWP_NOZORDER); 
     m_bRepaint = false; 
    } 

Die Verwendung von Invalidate() funktioniert nicht.Ich muss es auf etwas anderes als seine gegenwärtige Größe ändern und es zurück ändern.

Diese CDHtmlDialog Klasse ist ein PITA zu arbeiten, und ich würde niemandem empfehlen, es zu verwenden, wenn sie die Wahl haben.

+0

Ohne [mcve] können wir nur raten. – theB

+0

@theB, wenn ich das tun könnte, wäre ich prolly fertig. Einige mögliche Vorschläge wären nett. – Adrian

+0

Wenn Sie kein [mcve] bereitstellen können, geben Sie bitte das entsprechende Code-Snippet an. –

Antwort

0

Ok, so ist es, dass dies durch die Fenster Nachrichtenwarteschlange nicht deterministisch ist, verursacht wird, scheinen würde, so ist es, dass die zugrunde liegenden COM Kontrolle scheinen würde, ist Malerei auf es ist DC vor der WM_PAINT Nachricht.

Um das Problem zu umgehen, ich warte auf das Fenster selbst für WM_WINDOWPOSCHANGED Nachricht, indem er wartet zu zeigen, eine andere Anwendung Nachricht veröffentlichen, die dann Invalidate() und UpdateWindow() nennen, damit die Neuzeichnung des Fensters zu zwingen.

Diese Technik wird in Raymond Chens Blog "The Old New Thing" beschrieben here.

-1

Da OnEraseBkgnd() vor OnPaint genannt()

ON_WM_ERASEBKGND() 
... 

BOOL CCalcDrillDownDlg::OnEraseBkgnd(CDC* pDC) 
{ 
    // TODO: Add your message handler code here and/or call default 
    return TRUE; 
} 
+0

Also, ich bin mir nicht sicher, was Sie sagen, ich bin hier zu tun.Wenn 'OnEraseBkgnd() vor OnPaint()' aufgerufen wird, dann warum würde es nicht nur das Fenster nach dem Löschen löschen? Und warum wird es gelöscht? – Adrian

+0

In CDHtmlDialog, OnPaint() ist unwirksam, um Redraw durchzuführen. Normalerweise wird die HTML-Seite die beliebige Zeichnung überlagern, so dass es nicht neu gezeichnet werden kann. Nicht genug Informationen, um es weiter zu beweisen. –

+0

Ok, wenn das der Fall ist, sagst du, dass man 'OnEraseBkgnd()' anstelle von 'OnPaint()' verwenden soll? – Adrian