19 Stimmen

Wie ruft man eine Methode im Fenster (.xaml.cs) vom ViewModel (.cs) in WPF auf, ohne neue Referenzen einzuführen?

Ich suche nach einer einfachen Möglichkeit, eine Methode in meinem Hauptfenster aufzurufen, möchte sie aber von meinem ViewModel aus aufrufen. Grundsätzlich suche ich nach einer Art "this.parent" ähnlichen Sache, die ich im ViewModel platzieren kann, um auf das Hauptfenster zu verweisen.

Oder, wenn Sie den Grund erfahren möchten, warum ich dies tun möchte, und mir einen anderen Weg vorschlagen wollen, mein Problem anzugehen:

Ich arbeite mit einer App, die ständig mit Informationen versorgt wird. Im ViewModel werden die Informationen verarbeitet. Ich möchte jedes Mal eine Benachrichtigung machen, wenn eine Information eingeht, die bestimmte Kriterien erfüllt.

Zunächst hatte ich in meinem ViewModel ein Dictionary, das Informationen über diese Information speicherte, und ich griff auf dieses Dictionary im Hauptfenster zu, um das Fenster aufblinken zu lassen und andere Benachrichtigungen zu senden. Aber ich hatte Probleme damit, dass das Dictionary im ViewModel kontinuierlich geändert wurde, während ich darauf im Hauptfenster zugriff.

Entschuldigung, wenn diese Frage dumm klingt. Ich habe vor zwei Monaten mit WPF angefangen und hatte auch davor keine große Programmiererfahrung.

32voto

Dean Kuga Punkte 11481

VM sollte "nichts" von Ihrer Ansicht oder Ihrem Fenster wissen, die Art und Weise, wie VM in WPF/MVVM typischerweise mit V kommuniziert, erfolgt durch das Auslösen von Ereignissen. Auf diese Weise bleibt VM unwissend von/entkoppelt von V und da VM bereits DataContext von V ist, ist es nicht schwer, sich für das Ereignis von VM anzumelden.

Beispiel:

VM:

public event EventHandler> DoSomething;
...
Notify(DoSomething, new NotificationEventArgs("Nachricht"));

V:

var vm = DataContext as SomeViewModel; // VM aus dem DataContext der Ansicht erhalten
if (vm == null) return; // Überprüfen, ob die Konvertierung erfolgreich war
vm.DoSomething += DoSomething; // Beim Ereignis anmelden

private void DoSomething(object sender, NotificationEventArgs e)
{
    // Code    
}

14voto

Lance Punkte 2388

Zunächst einmal ist es keine dumme Frage. Die meisten MVVM-Anfänger kommen von WinForms und es ist normal, die Tendenz zu haben, ihre WinForms-Praktiken einzubringen und im Code-Bereich zu arbeiten. Jetzt müssen Sie das einfach vergessen und an MVVM denken.

Zu Ihrer Frage zurückkehrend: Sie haben ein Wörterbuch, das Ihr VM verarbeitet, und Sie greifen auf dieses Wörterbuch von der Ansicht aus zu. Ihre Ansicht sollte keine Ahnung von Ihrem ViewModel haben, außer durch Bindung.

Das Blinken eines Fensters, wenn es Änderungen im ViewModel gibt, klingt für mich nach einem angehängten Verhalten. Hier ist ein guter Artikel über angehängtes Verhalten. http://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

Um es einfacher zu machen, werde ich Ihnen ein sehr einfaches Beispiel geben, das irgendwie relevant für Ihren Fall sein wird.

Erstellen Sie eine angehängte Verhaltensklasse, in der Sie ein IEnumerable haben, wobei jedes Mal, wenn Sie etwas hinzufügen, eine MessageBox auf dem Bildschirm erscheint. Ändern Sie einfach den MessageBox-Code in die gewünschte Blinkanimation bei Benachrichtigung.

public class FlashNotificationBehavior
{
    public static readonly DependencyProperty FlashNotificationsProperty =
        DependencyProperty.RegisterAttached(
        "FlashNotifications",
        typeof(IEnumerable),
        typeof(FlashNotificationBehavior),
        new UIPropertyMetadata(null, OnFlashNotificationsChange));

    private static void OnFlashNotificationsChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var collection = e.NewValue as INotifyCollectionChanged;

        collection.CollectionChanged += (sender, args) => 
            {
                if (args.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (var items in args.NewItems)
                        MessageBox.Show(items.ToString());
                }
            };            
    }

    public static IEnumerable GetFlashNotifications(DependencyObject d)
    {
        return (IEnumerable)d.GetValue(FlashNotificationsProperty);
    }

    public static void SetFlashNotifications(DependencyObject d, IEnumerable value)
    {
        d.SetValue(FlashNotificationsProperty, value);
    }
}

In Ihrem ViewModel können Sie eine ObservableCollection-Eigenschaft erstellen, Sie benötigen eine ObservableCollection, damit eine Sammlungsänderungsbenachrichtigung erfolgt. Ich habe auch ein Command zum Hinzufügen hinzugefügt, damit Sie es testen können.

   public class MainViewModel : ViewModelBase
{
    ObservableCollection notifications;

    public ObservableCollection Notifications
    {
        get { return notifications; }
        set
        {
            if (notifications != value)
            {
                notifications = value;
                base.RaisePropertyChanged(() => this.Notifications);
            }
        }
    }

    public ICommand AddCommand
    {
        get
        {
            return new RelayCommand(() => this.Notifications.Add("Hello World"));
        }
    }

    public MainViewModel()
    {
        this.Notifications = new ObservableCollection();             
    }
}

Und hier ist eine Ansicht, in der Sie die Notifications-Eigenschaft aus Ihrem ViewModel binden können.

        Etwas hinzufügen

Jedes Mal, wenn Sie etwas zur ObservableCollection hinzufügen, erhalten Sie eine MessageBox, die den Benutzer darüber informiert, dass etwas zu Ihrer Sammlung hinzugefügt wurde.

Ich hoffe, dass ich Ihnen bei Ihrem Problem geholfen habe. Sagen Sie mir einfach Bescheid, wenn Sie weitere Erklärungen benötigen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X