Laden...

MVVMLight ViewModelLocator Instanz des Datakontextes zurück setzten.

Letzter Beitrag vor 9 Jahren 7 Posts 3.395 Views
MVVMLight ViewModelLocator Instanz des Datakontextes zurück setzten.

Hallo,

ich nutze zum ersten mal den ViewModelLocator aus dem MVVM Light in einen Projekt. Ich bin bisher davon ausgegangen, das der synonym für diesen Aufruf gilt.


public partial class DBConnectionView : ExWindow
    {
        public DBConnectionView()
        {
            InitializeComponent();
            //this.DataContext = new SQLConnectionViewModel();
        }
    }

Aber scheinbar ist dem nicht so. Nach langer Suche im Internet und dutzenden Versuchen war ich bisher leider erfolglos bei der Problembehebung. Ich habe ein Fenster abgeleitet und dort direkt ein Event registriert. Dieses feuert jedoch direkt, wenn ich das Fenster ein zweites mal Öffne. Es ist offensichtlich so, das das ViewModel irgendwie gecached wird und wiederverwendet.

Ich habe in der App.xaml das ViewModel registriert und im Fenster wie in dutzenden Beispielen gelesen, aufgerufen. Wo liegt mein Denkfehler? Jemand eine gute Idee?

<SO:ExWindow x:Class="SQLiteAdministrator.View.DBConnectionView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:SO="clr-namespace:SharedObjects;assembly=SharedObjects"
        xmlns:vm="clr-namespace:SQLiteAdministrator.ViewModel"
        WindowStartupLocation="CenterScreen"
        DialogValue="{Binding DialogValue}"
        DataContext = "{Binding Source={StaticResource Locator}, Path=SQLConnectionViewModel}"
        Title="DBConnectionView" Height="600" Width="600"

Gruß dat Tala

ein event feuert, wenn gecodet ist, dass es feuern soll.
also hast du es wohl so gecodet, dass es bei Anzeige des ExWindows feuert.

Mir scheint, was du als Infos zur Frage einbringst , ist evtl. gar nicht relevant .

Der frühe Apfel fängt den Wurm.

Oky. Dann hier der Code.


public class DialogWindow : Window 
    {
        public DialogWindow() : base() 
        {
            this.DialogValue = null;
            this.DialogValueChanged += DialogWindow_DialogValueChanged;
        }

        
        public object DialogValue
        {
            get { return (object)GetValue(DialogValueProperty); }
            set { SetValue(DialogValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DialogValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DialogValueProperty =
            DependencyProperty.Register("DialogValue", typeof(object), typeof(DialogWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnDialogValueChanged)));



        private event DependencyPropertyChangedEventHandler DialogValueChanged;

        private static void OnDialogValueChanged(DependencyObject sender, 
                               DependencyPropertyChangedEventArgs e)
        {
            DialogWindow dialogWindow = (DialogWindow)sender;
            
            if (dialogWindow.DialogValueChanged != null)
                dialogWindow.DialogValueChanged(dialogWindow, e);
        }

        private void DialogWindow_DialogValueChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue == null)
                this.DialogResult = false;
            else this.DialogResult = true;
            
        }

        protected override void OnClosed(EventArgs e)
        {
            this.DialogValueChanged -= DialogWindow_DialogValueChanged;
            base.OnClosed(e);
        }

    }

Das Event feuert halt sofort, sobald ich das Fenster einmal mit über das Event geschlossen habe. Was natürlich unpraktisch ist. Ich kann es nicht mal irgendiwe nullen oder zurück setzten.

Gruß dat Tala

@ErfinderDesRades : Ich habe deinen Ansatz mit der Event(feuerung) verfolgt. Bin mir aber ziemlich sicher, das es nicht gewollt 2x auslößt. Denn die entsprechende Property gibt beim zweiten Aufruf wieder den ersten wert zurück.

 DBConnectionView view1 = new DBConnectionView();
                if (view1.ShowDialog() == true)
                {
                    
                }
                view1 = null;

                DBConnectionView view2 = new DBConnectionView();
                view2.ShowDialog();

Die Eigenschaft ReturnValue von DBConnectionView sollte beim zweiten Aufruf wieder den Standard-Wert haben, hat er aber nicht. Denn er gibt (wieder) den wert vom view1 zurück. Daher vermute ich den Fehler irgendwo im ViewModel. Da das Viewmodel keine eigene Instanz erzeugt, je Fenster.

Gruß dat Tala

zunächst mal findichs eigenartig, einen Dialog an ein globales Viewmodel zu binden.
Bei mir hat ein Dialog ein eigenes Viewmodel, was mit ihm erstellt und auch mit ihm zerstört wird.
Weil bei mir will ich den Dialog auch canceln können, der soll mir nicht per Databinding in meim globalen Viewmodel rumschreiben.

Aber ich bin auch verwirrt mit deiner event-Konstruktion: zum statischen Event der DependancyProperty noch ein privates Event - bist du dir ganz sicher, dass das nicht einfacher und übersichtlicher geht?

Der frühe Apfel fängt den Wurm.

Hi,

also zu den Events. Nein bin ich nicht, aber ich weiß auch nicht, wie ich es anders machen könnte. Habe nichts weiteres dazu gefunden. Bei normalen Eigenschaften hätte ich das einfach in den Setter mit rein geschrieben.

Und ein globales ViewModel will ich eben gerade nicht. Aber es scheint genau das zu sein. Es wird eines instanziert im ViewModelLocator und eben jenes verwendet. Es liegt an dieser GetInstance Funktion des ServiceLocator.

 public MainWindowViewModel DatabaseViewModel
        {
            get
            {
                // Geändert
                return new MainWindowViewModel();
                // Ursache
                //return ServiceLocator.Current.GetInstance<MainWindowViewModel>();
            }
        };

Gruß dat Tala

also zu die Events: So scheint mir einfacher:

using System.Windows;
using System;
public class DialogWindow : Window {

   public static readonly DependencyProperty DialogValueProperty =
       DependencyProperty.Register("DialogValue", typeof(object), typeof(DialogWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnDialogValueChanged)));
   public object DialogValue {
      get { return (object)GetValue(DialogValueProperty); }
      set { SetValue(DialogValueProperty, value); }
   }
   private static void OnDialogValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {
      ((DialogWindow)sender).OnDialogValueChanged(e);
   }
   private void OnDialogValueChanged(DependencyPropertyChangedEventArgs e) {
      this.DialogResult = e.NewValue == null;
   }
}

zum globalen Viewmodel: naja, der Locator-Pattern ist nunmal der Pattern eines globalen Viewmodels.
Und also hier vlt. nicht angezeigt.

Der frühe Apfel fängt den Wurm.