Laden...

MVVM Light - Objekte sind zur Laufzeit sichtbar, zur Designzeit nicht

Erstellt von DeSharper vor 7 Jahren Letzter Beitrag vor 6 Jahren 3.802 Views
D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 7 Jahren
MVVM Light - Objekte sind zur Laufzeit sichtbar, zur Designzeit nicht

Kennt sich irgendjemand mit MVVM Light aus? Ich komme hier wirklich nicht mehr weiter. Ich möchte OberflächenObjekte in meinem eigenen Panel anordnen, das alles funktioniert zur Laufzeit auch wunderbar, aber zur DesignZeit ist mein Fenster leer. Ich habe mein Problem jetzt schon aufs Einfachste zusammengeschrumpft, es scheint ein Problem mit meinem eigenen Panel zu geben, sicher bin ich mir aber nicht.
Kann mir jemand sagen, was ich falsch mache und warum es zur Laufzeit dann doch funktioniert?

Ausschnitt aus Window


    <Window.DataContext>
        <Binding Path="TestWindowVm" Source="{StaticResource Locator}"/>
    </Window.DataContext>
    
    <Grid>
        <ItemsControl ItemsSource="{Binding Path=MyList}"
                      ItemTemplate="{DynamicResource TestTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <userControls:MySimplePanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>

Wenn ich hier statt userControls:MySimplePanel zum Beispiel DockPanel einsetzte, sehe ich auch zur DesignZeit was.

Und hier kommt der Hauptverdächtige, MySimplePanel:


    public class MySimplePanel: Panel
    {
        private const double OVERLAP = 0.5;

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size(0, 0);
            double überlappungsfaktor = 1; // erstes Element volle Breite

            foreach (FrameworkElement child in this.InternalChildren)
            {
                child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

                desiredSize.Width += child.DesiredSize.Width * überlappungsfaktor;
                überlappungsfaktor = OVERLAP;

                if (desiredSize.Height < child.DesiredSize.Height)
                {
                    desiredSize.Height = child.DesiredSize.Height;
                }
            }

            return desiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            Point childPos = new Point(0, 0);

            foreach (FrameworkElement child in this.InternalChildren)
            {
                child.Arrange(new Rect(childPos, child.DesiredSize));

                childPos.X += child.DesiredSize.Width * OVERLAP;
            }

            return finalSize;
        }
    }

Zugehöriges ViewModel:


    public class TestWindowViewModel : ViewModelBase
    {
        public ObservableCollection<String> MyList{ get; set; }

        public TestWindowViewModel()
        {
            if (IsInDesignMode)
            {
                this.MyList= new ObservableCollection<String>();
                this.MyList.Add("schokoKeks");
                this.MyList.Add("halloEcho");
                this.MyList.Add("Wololooo");
                this.MyList.Add("DumDidldum");
            }
            else
            {
                this.MyList= new ObservableCollection<String>();
                this.MyList.Add("schokoKeks");
                this.MyList.Add("halloEcho");
                this.MyList.Add("Wololooo");
                this.MyList.Add("DumDidldum");
            }
        }
    }

Ressourcen:


    <DataTemplate x:Key="TestTemplate" DataType="sys:String">
        <Grid>
            <Rectangle Width="150" Height="350" Fill="GreenYellow" Stroke="Black"/>
            <TextBlock Text="{Binding}" 
                      VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,0,0" 
                      TextWrapping="Wrap"/>
        </Grid>
    </DataTemplate>

1.040 Beiträge seit 2007
vor 7 Jahren

Wenn es mit einem normalen Panel geht, dann liegt es schon mal nicht an MVVM-Light. 😉

Du kannst die beiden überschriebenen Methoden mal step-by-step aufbauen bzw. durcharbeiten, um zu gucken was dort passiert.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 7 Jahren

Update:
Ich habe inzwischen auch mein Panel bis zur Sinnlosigkeit zusammengeschrumpft. Ich weiß nicht, woran sich der DesignMode hier noch stoßen könnte.


        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size(100, 100);

            return desiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (FrameworkElement child in this.InternalChildren)
            {
                Rect rect = new Rect(new Point(0,0), new Size(100,100));
                child.Arrange(rect);
            }

            return finalSize;
        }

Das Problem besteht leider nur zur DesignZeit. Deswegen hilft mir hier auch der Debugger nichts - nichtmal irgendwelche Konsolenausgaben. Ich wüsste jedenfalls nicht wie. Wenn du irgendeine Möglichkeit weißt, wie man das debuggen kann, nur her damit.

Eigentlich sollte mir MVVM Light helfen meine ObservableCollection auch schon zur DesignZeit mit Objekten zu füllen, die mein ItemsControl dann darstellen kann. Weil es eben in vielen Fällen - zum Beispiel bei einem eigenen Panel - ziemlich umständlich ist, für das optische Ergebnis immer erst das Programm starten zu müssen. Genau dieses MVVM Light feature funktioniert bei mir nicht. Ob das Problem bei MVVM Light liegt oder allgemein beim DesignModus, weiß ich nicht. Vielleicht / möglicherweise / wahrscheinlich liegt das an meinem Panel, ich weiß aber nicht, was genau ich in diesem Panel tue, was im DesignModus nicht geht. Deswegen frage ich, weil ich einfach keine Plan mehr habe, wie ich diesem Problem auf den Grund gehen kann.

Anmerkung:
Möglicherweise hat das zu Missverständnissen geführt. Wenn ich DesingZeit sage, meine ich DesingMode / Entwurfszeit / NICHT-Laufzeit eben. 😃

5.657 Beiträge seit 2006
vor 7 Jahren

Wann genau entsteht das Problem? Wenn du <userControls:MySimplePanel /> anstatt <Panel /> benutzt, oder wenn du die beiden Methoden aus deinem letzten Beitrag in die MySimplePanel-Klasse einbaust?

Weeks of programming can save you hours of planning

1.040 Beiträge seit 2007
vor 7 Jahren

Geht es, wenn du ein normales Panel benutzt?
Geht es, wenn du ein abgeleitetes Panel - OHNE Overrides - benutzt?

Wenn du beide Fragen mit JA beantworten kannst, liegt es an dem minimalen Code der MeasureOverride- und ArrangeOverride-Methoden.

Du kannst übrigens auch das Visual Studio debuggen, wenn du dich mit einem anderen Visual Studio an die andere Instanz hängst. 😁

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

@MrSparkle:
Das Problem taucht auf, wenn ich mein eigenes Panel <userControls:MySimplePanel> anstatt <Panel> verwende. Die beiden Methoden aus meinem letzten Beitrag ändern daran nichts. Sie waren nur ein Versuch auszuschließen, dass das Problem in diesen Methoden liegt. Das Problem besteht aber weiterhin sowohl mit den ausführlicheren Methoden aus meinem ersten Post als auch mit den extrem verkürzten Methoden.

@p!lle:
Mit einem normalen Panel (DockPanel oder Grid, Panel geht natülich nicht, weils abstrakt ist, mehr hab ich jetzt mal nicht getestet) funktioniert alles wunderbar.
Wenn ich die MeasureOverride und ArrangeOverride auskommentiere bleibt der Fehler bestehen. In MySimplePanel steht jetzt überhaupt kein Code mehr und ich hab außerdem noch getestet, ob es vielleicht funktioniert, wenn ich statt von Panel von DockPanel erbe, weil das abstrakte Panel alleine nicht geht. Hab aber in keinem Fall eine Vorschau im DesignModus bekommen.

Letzter Test, alles bleibt wie es ist, ursprünglicher Code, aber ich erbe von DockPanel, statt von Panel. Überraschung: Ich habe ein Bild im DesignModus, aber es ist die Anordnung, die ich von DockPanel erwarten würde. Zur Erinnerung: ICh überschreibe immernoch ArrangeOverride und MeasureOverride. Zur Laufzeit bekomme ich übrigens auch das richtige Ergebnis (kein DockPanel sondern MySimplePanle). Ich bin verwirrt und müde, aber das könnte eine Spur sein. 😃

301 Beiträge seit 2009
vor 6 Jahren

Macht es einen Unterschied wenn du den Call base.OverridenMethod() mit in deine Methoden einbaust?

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

Nein, das macht keinen Unterschied. Im DesignModus scheint die Tatsache, dass ich diese Methode überschreibe einfach vollständig ignoriert zu werden.

Aber bei einem Test zu deiner Frage ist mir nochwas aufgefallen. Ich glaube mein eigenes Panel ist völlig unschuldig. Wenn ich für das ItemsControl statt meines eigenen Panels ein DockPanel verwende, dann sehe ich zwar zur DesignZeit was, aber auch nicht das gleiche wie live. Die Liste, die ich im ViewModel erstelle (siehe erster post), ist mit Werten gefüllt, die nicht von mir kommen. Statt "schokokeks" und so, heißen sie nur "1", "2" und "3".
Mein Problem hat sich also auf die Frage reduziert, warum obwohl ich für den DesignModus die gleiche Liste erzeuge wie zur Laufzeit (siehe unten), diese Liste offenbar mit vollkommen anderen Werten gefüllt wird. Aber gefüllt wird sie, sie ist ja offenbar nicht leer. Aber wo zum Teufel kommen "1", "2" und "3" her?

Zugehöriges ViewModel:

C#-Code:

 public class TestWindowViewModel : ViewModelBase
{
    public ObservableCollection<String> MyList{ get; set; }

    public TestWindowViewModel()
    {
       if (IsInDesignMode)
       {
            this.MyList= new ObservableCollection<String>();
            this.MyList.Add("schokoKeks");
            this.MyList.Add("halloEcho");
            this.MyList.Add("Wololooo");
            this.MyList.Add("DumDidldum");
        }
        else
        {
            this.MyList= new ObservableCollection<String>();
            this.MyList.Add("schokoKeks");
            this.MyList.Add("halloEcho");
            this.MyList.Add("Wololooo");
            this.MyList.Add("DumDidldum");
        }
    }
}
Hinweis von Coffeebean vor 6 Jahren

Bitte benutze dir richtigen Code-Tags [Hinweis] Wie poste ich richtig?

301 Beiträge seit 2009
vor 6 Jahren
d:DataContext="{d:DesignInstance vm:MyDesignTimeViewModel, IsDesignTimeCreatable=true}"

Probier das mal in deiner View oben mit einzusetzen. Das nutze ich immer wenn ich Intellisense im XAML haben möchte. Ggf. beeinflusst das auch den Designer? Genaues kann ich sonst nicht sagen ohne selbst dein Projekt zu haben. Ich arbeite selbst auch gar nicht mehr mit dem Designer.

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

Hat leider auch nicht funktioniert. Ich hab jetzt den bisherigen DataContext ausdkommentiert und nur das mti der DesingInstance drin, aber das Ergebnis bleibt unverändert. Schade, die Idee klang vielversprechend.

5.299 Beiträge seit 2008
vor 6 Jahren

erb doch spasseshalber mal von DockPanel

Ich könnte mir vorstellen, die funktionierenden Standard-Panels haben iwelche Attribute mit Informationen für den Xaml-Designer

Der frühe Apfel fängt den Wurm.

1.040 Beiträge seit 2007
vor 6 Jahren

Habe das Problem einmal schnell nachgebaut:
Ich sehe die grünen Einträge, allerdings auch nur 1, 2, 3... Code aus dem ersten Beitrag wurde genutzt.

Wo hast du die Ressourcen definiert?

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

Von DockPanel erben hab ich schon versucht (siehe zweiter Post, letzer abschnitt).

Meinst du das Template? Das liegt in einem ResourceDictionary, welches ich im Window an anfang einbinde. Den Code hatte ich unterschlagen 😃 Das ist allerdings das einzige, was ich noch nicht vereinfacht hab.


<Window.Resources>
    <ResourceDictionary x:Name="CurrentResourceDictionary">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/StylingResources/Theme_Simple.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>


Das sieht ein bisschen komisch aus, weil ich die StylingRessourcen zur Laufzeit austauschen können will. Ich hab jetzt erstmal Window.Resources... komplett auskommentiert, die Darstellung ist jetzt zusammengeschrumpft auf 123, wenn ich von DockPanel erbe und keine Darstellung wenn ich von Panel erbe. Das scheint also auch nicht das Problem zu sein.

5.299 Beiträge seit 2008
vor 6 Jahren

Von DockPanel erben hab ich schon versucht (siehe zweiter Post, letzer abschnitt). sorry - kannst du das verlinken? Wie immer ich "2. Postm letzter Abschnitt" auch aiuffasse, von Erben von Dockpanel finde ich da nix.

Der frühe Apfel fängt den Wurm.

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

kannst du auch nicht, ich war zu blöd zum zählen, sorry

Letzter Test, alles bleibt wie es ist, ursprünglicher Code, aber ich erbe von DockPanel, statt von Panel. Überraschung: Ich habe ein Bild im DesignModus, aber es ist die Anordnung, die ich von DockPanel erwarten würde. Zur Erinnerung: ICh überschreibe immernoch ArrangeOverride und MeasureOverride. Zur Laufzeit bekomme ich übrigens auch das richtige Ergebnis (kein DockPanel sondern MySimplePanle).

Also es hat einen Effekt von einem nicht abstrakten Panel zu erben, aber meine überschriebenen Methoden werden einfach ignoriert.

D
DeSharper Themenstarter:in
40 Beiträge seit 2016
vor 6 Jahren

Update:
Hab letzte Woche endlich auf Visual Studio 2017 umgestellt. Seitdem funktioniert alles tadellos. Problem gelöst.