Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

1

05.07.2016, 00:54

[C# WPF] Content-Änderung soll Parent aktualisieren [gelöst]

Moin Leute,

es geht um ein UserControl A, das in einem UserControl B ist - als Content. Ein drittes UserControl C soll nun in A eingefügt werden. Dazu ruft C die DropPanel Methode (mit sich selbst als droppedPanel) von A auf. Ich mache keinen gebrauch von der Windows eigenen DragDrop-Mechanik, weil die Funktionalität, die ich brauche damit nicht funktioniert. Soll auch bitte kein Thema in diesem Thread sein! ;)

Wenn DropType == Top ist, dann soll in B ein VerticalWindowPanel eingefügt werden, das nun A und C enthält. Für Bottom das Ganze andersrum. Ich habe folgenden Code:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public override void DropPanel(BaseWindowPanel droppedPanel, DropType dropType)
{
    BaseWindowPanel newParent;
    switch (dropType)
    {
        case DropType.Top:
            newParent = new VerticalWindowPanel()
            {
                BottomContent = this,
                TopContent = droppedPanel,
            };
            break;
        case DropType.Bottom:
            newParent = new VerticalWindowPanel()
            {
                BottomContent = droppedPanel,
                TopContent = this
            };
            break;
        // Noch ein paar andere cases nach ähnlichem Prinzip!
        default:
            return;
    }
    (Parent as ContentControl).Content = newParent;
}
Falls wer danach fragt:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public partial class VerticalWindowPanel : BaseWindowPanel
{
    // Eigenschaften
    public object TopContent
    {
        // TopContentControl ist vom Typ System.Windows.Controls.ContentControl
        get { return TopContentControl?.Content; }
        set { TopContentControl.Content = value; }
    }
    public object BottomContent
    {
        // BottomContentControl ist vom Typ System.Windows.Controls.ContentControl
        get { return BottomContentControl?.Content; }
        set { BottomContentControl.Content = value; }
    }
    // Anderer Code
}

Problem ist, dass der Code in Zeile 24 nie zurückkehrt und nach TaskManager-Kill (weil VS nicht mehr reagiert) eine StackOverflowException auslöst wird. Mit dem Debugger habe ich einen Haltepunkt vor dieser Anweisung gesetzt.

Dann ist mir aufgefallen, dass weder this, noch droppedPanel newParent als Parent gesetzt haben. newParent hat allerdings die beiden UserControls in seinen beiden ContentControls eingetragen. Wann wird die Parent-Eigenschaft vom System aktualisiert? Einen Setter hat diese Eigenschaft leider nicht und eine andere Möglichkeit eine Aktualisierung sofort zu erzwingen kann ich im Internet nicht finden. Meine Nachforschungen ergeben, dass ein ContentControl diesen Job für einen erledigt - aber WANN macht es das?

Falls irgendetwas unklar ist bitte schreibts mir! Ich weiß nicht wie (un)deutlich meine Formulierungen sind... habe ich ja schon öfters hier gemerkt.
Danke schonmal für die Antworten!
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »CeDoMain« (06.07.2016, 01:39)


TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

2

05.07.2016, 08:34

Sieht für mich auf den ersten Blick so aus, als ob das setzen des Content-Property die Methode DropPanel aufruft. Allerdings müsste man das im Stacktrace sehen. Kannst du den zeigen?

Du machst echt ungewöhnliche Dinge mit WPF :D

CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

3

05.07.2016, 14:41

Was ist schon gewöhnlich... ;)

Habe einen Haltepunkt in Zeile 24 gesetzt und nachdem dieser Haltepunkt angesprungen wurde ganz oben in der Methode einen weiteren gesetzt. Dann habe ich F11 gedrückt. Nach 36s völliger Reaktionslosigkeit von Visual Studio und meinem Programm sieht die Ansicht so aus wie auf dem angehangenen Screenshot. Es wurde in der zwischenzeit kein anderer Haltepunkt angesprungen. Der Stacktrace ist noch der Selbe wie vor dem Ausführen von Zeile 24. Die Anweisung ist also noch nicht zurückgekehrt.

Hoffe das hilft weiter. Soll ich vielleicht mal das Projekt hochladen? Dann verschicke ich das aber als PM - möchte das nicht veröffentlichen!
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

Toemsel

Treue Seele

Beiträge: 310

Wohnort: OÖ

Beruf: Student und Programmierer

  • Private Nachricht senden

4

05.07.2016, 15:00

Es gibt ein Fenster speziell für den Stacktrace. Wird glaube ich "Aufrufhierarchie" genannt. (Oder nur Hierarchie)
Denke die Methode DropPanel wird durch das erstellen eines neuen VerticalWindowPanel immer wieder im Konstruktor aufgerufen.
Der Parent wird nur dann gesetzt, wann du ihn auch explizit an ein Parent zuweist oder einfügt.

PS: Ich empfehle dir immer noch ein Framework. Wie viele Stunden verbringst du nun schon mit solch simplen Features?
PPS: Sorry, hab erst jetzt deinen letzten Beitrag gelesen. Stell das Projekt online oder schick es mir per PN. Ich schaus mir an.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Toemsel« (05.07.2016, 15:08)


TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

5

05.07.2016, 15:04

Wenn du ein Content-property setzt wird der UI-Thread vermutlich Measure() anstoßen, und wenn das nie Fertig wird (ich hatte auch mal so einen Bug mit einer ListBox von DataGrids in sehr seltenen Fällen).

Ja schick das Projekt per PN, ich gucks mir heute oder morgen an.

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

6

05.07.2016, 15:47

Also ich konnte den Code problemlos durchlaufen, allerdings kriege ich andere, seltsame Exceptions:

Zitat

Der Assistent für verwaltetes Debugging ""NotMarshalable"" hat ein Problem in ""C:\Users\Test\Downloads\Source\frontend\bin\Debug\Frontend.vshost.exe"" festgestellt.

Zusätzliche Informationen: Eine COM-Komponente, die nicht gemarshallt werden kann, wird von einem anderen Apartment/Kontext aus verwendet, als dem, in dem sie erstmals in die CLR eingetreten ist. Da die Komponente nicht gemarshallt werden kann, wird sie direkt vom aktuellen Apartment/Kontext aufgerufen. Dies kann Datenbeschädigung oder -verlust zur Folge haben, wenn die Komponente den gleichzeitigen Zugriff durch mehrere Threads nicht unterstützt. Die wahrscheinlichste Ursache ist eine fehlerhafte IMarshal-Implementierung seitens der COM-Komponente.


Kriegst du die auch?

Toemsel

Treue Seele

Beiträge: 310

Wohnort: OÖ

Beruf: Student und Programmierer

  • Private Nachricht senden

7

05.07.2016, 15:56

Also ich konnte den Code problemlos durchlaufen, allerdings kriege ich andere, seltsame Exceptions:

Zitat

Der Assistent für verwaltetes Debugging ""NotMarshalable"" hat ein Problem in ""C:\Users\Test\Downloads\Source\frontend\bin\Debug\Frontend.vshost.exe"" festgestellt.

Zusätzliche Informationen: Eine COM-Komponente, die nicht gemarshaBellt werden kann, wird von einem anderen Apartment/Kontext aus verwendet, als dem, in dem sie erstmals in die CLR eingetreten ist. Da die Komponente nicht gemarshallt werden kann, wird sie direkt vom aktuellen Apartment/Kontext aufgerufen. Dies kann Datenbeschädigung oder -verlust zur Folge haben, wenn die Komponente den gleichzeitigen Zugriff durch mehrere Threads nicht unterstützt. Die wahrscheinlichste Ursache ist eine fehlerhafte IMarshal-Implementierung seitens der COM-Komponente.


Kriegst du die auch?


Bekomme ich auch. :thumbsup: Vll. hat CeDoMain andere Exception settings.

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

8

05.07.2016, 15:59

Ja das hab ich schon reparieren können, kann man in den Optionen das UI Debugging deaktiveren. Ich bekomme den Fehler beim zweiten mal etwas Docken reproduziert. Du schaffst es, dass sich WPF zu Tode aktualisiert, daher reagiert auch nix (UI-Thread). Ich vermute, WPF dreht sich im Kreis beim Updaten und meine Heiße vermutung ist: es liegt an den Events, die du abfängst und wieder feuerst (nach erstem groben Scannen). Genau mit solchem Code habe ich auch schonmal eine WPF Anwendung zum Stackoverflow getrieben.

Hier der StackTrace (auszug):

Zitat

> PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkLogicalChildren(System.Windows.FrameworkElement feParent, System.Windows.FrameworkContentElement fceParent, System.Collections.IEnumerator logicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkFrameworkElementLogicalThenVisualChildren(System.Windows.FrameworkElement feParent, bool hasLogicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.IterateChildren(System.Windows.DependencyObject d) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkLogicalChildren(System.Windows.FrameworkElement feParent, System.Windows.FrameworkContentElement fceParent, System.Collections.IEnumerator logicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkFrameworkElementLogicalThenVisualChildren(System.Windows.FrameworkElement feParent, bool hasLogicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.IterateChildren(System.Windows.DependencyObject d) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkLogicalChildren(System.Windows.FrameworkElement feParent, System.Windows.FrameworkContentElement fceParent, System.Collections.IEnumerator logicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkFrameworkElementLogicalThenVisualChildren(System.Windows.FrameworkElement feParent, bool hasLogicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.IterateChildren(System.Windows.DependencyObject d) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkLogicalChildren(System.Windows.FrameworkElement feParent, System.Windows.FrameworkContentElement fceParent, System.Collections.IEnumerator logicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkFrameworkElementLogicalThenVisualChildren(System.Windows.FrameworkElement feParent, bool hasLogicalChildren) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.IterateChildren(System.Windows.DependencyObject d) Unbekannt
PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d, bool visitedViaVisualTree) Unbekannt


EDIT: Wenn du irgendwie ein Kind wieder einem Vater als Kind zuweist, dann würde es den Fehler erklären. Tipp: Logge alle Eventhandler Mit Typ, Methode und einer Objekt-Id (erstelle einen static zähler) in eine Datei (schön schließen nach jedem Write), dann findet sich der Fehler bestimmt ;)

Toemsel

Treue Seele

Beiträge: 310

Wohnort: OÖ

Beruf: Student und Programmierer

  • Private Nachricht senden

9

05.07.2016, 16:38

Wie bereits in der PM erklärt: Der Fehler liegt an der Zuweisung:

C#-Quelltext

1
2
3
4
5
6
7
8
newParent = new VerticalWindowPanel()
{
    BottomContent = this,
    TopContent = droppedPanel
};
break; 

(Parent as ContentControl).Content = newParent;


Dadurch dreht sich der Code im Kreis.
Auflösung durch z.B

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
case DropType.Top:
    newParent = new VerticalWindowPanel()
    {
       TopContent = droppedPanel,
    };
    break; 
.
.
.
if (Windowed)
    newParent.Windowed = true;
    else
    {
       (Parent as ContentControl).Content = newParent;
       if (newParent.GetType().Equals(typeof(VerticalWindowPanel)) && dropType == DropType.Top)
          ((VerticalWindowPanel)newParent).BottomContent = this;
    }


Sehr schlechte Lösung. Soll nur demonstrieren, dass der BottomContent nach der Parent Zuweisung stattfinden sollte.

CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

10

06.07.2016, 00:42

es liegt an den Events, die du abfängst und wieder feuerst
Beispiel? Ich habe Events, aber die sind in einem anderen Teil des Codes und feuern sich nicht selbst wieder... (Kannst du mir per PM beantworten. ;) )

Wie bereits in der PM erklärt: Der Fehler liegt an der Zuweisung: [...] Dadurch dreht sich der Code im Kreis.

C#-Quelltext

1
2
3
4
5
6
7
8
newParent = new VerticalWindowPanel()
{
    BottomContent = this,
    TopContent = droppedPanel
};
break; 

(Parent as ContentControl).Content = newParent;
Jap verstehe das Problem! Bin gerade nochmal mit dem Debugger durchgesteppt und habs mir angeschaut. Mein Code an sich ist aber nicht logisch falsch. Der Auslöser ist doch, dass die Parent-Eigenschaft von this nicht sofort richtig geändert wird. Ich probiere mal weiter rum, ob sich diese Bindung nicht doch sofort aufbrechen lässt. Vielleicht durch eine Parent.Content = null Zuweisung...
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

Werbeanzeige