Entwickler-Ecke
WPF / Silverlight - Methode aus Window aus Page ausführen
Cabur - Mi 23.10.19 23:05
Titel: Methode aus Window aus Page ausführen
Hallo zusammen,
bis jetzt konnte mir schon oft geholfen werden, indem ich Beiträge mitgelesen habe. Aber jetzt stehe ich vor ein Problem, zu dem ich keine Lösung finden konnte. Ich hoffe die Überschrift ist verständlich genug.
Ich habe eine MainWindow (welches beim Start des Programms geöffnet wird) und das dazugehörige ViewModel. In dem MainWindow wir in einem Frame eine Page (auch mit dazugehörigem ViewModel)geöffnet. In dem MainWindow gibt es zudem ein Panel, welches zu Beginn nicht angezeigt wird, aber bei Bedarf ähnlich wie ein Popup-Fenster eingeblendet und über alle anderen Controls des MainWindows gelagert werden soll. (Es soll explizit kein neues Fenster sein!) Über einen Button im MainWindow klappt das auch soweit ganz gut. Jetzt möchte ich aber in der Page auch ein Button hinzufügen, mit dem ich das Panel im MainWindow ein- und ausblenden kann. Und genau da besteht mein Problem. Das bekomme ich nicht hin. Die MessageBox wird angezeigt, "OpenPanelAttribute" wird auch auf "Visible" gesetzt, das Panel aber nicht sichtbar.
Ich hoffe, ich habe mich verständlich ausgedrückt.
Mein MainWindowViewModel:
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38:
| public class MainWindowViewModel : BaseViewModel { public NavigationService nav; public RelayCommand CmdOpenPage { get; private set; } public RelayCommand CmdOpenPanel { get; private set; }
public MainWindowViewModel() { OpenPanelAttribute = "Collapsed"; CmdOpenPanel = new RelayCommand(OpenPanel); CmdOpenPage = new RelayCommand(OpenPage); }
private string openPanelAttribute; public string OpenPanelAttribute { get { return openPanelAttribute; } set { if (value != openPanelAttribute) { openPanelAttribute = value; OnPropertyChanged("OpenPanelAttribute"); } } }
private void OpenPage(object open) { nav.Navigate(new PageView()); }
private void OpenPanel(object open) { MessageBox.Show("Testbox", "Überschrift", MessageBoxButton.OK); OpenPanelAttribute = "Visible"; } } |
Mein PageViewModel:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| public class PageViewModel : BaseViewModel { public RelayCommand CmdOpenMainPanel;
public PageViewModel { CmdOpenMainPanel = new RelayCommand(OpenMainPanel); }
private void OpenMainPanel(object open) { } } |
Cabur - Fr 25.10.19 17:30
Hier der Ausschnitt aus meiner XAML-Datei:
XML-Daten
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| <Canvas x:Name="MainWindow"> <DockPanel x:Name="Menu"> </DockPanel>
<DockPanel x:Name="OpenPanel" Background="Red" Visibility="{Binding OpenPanelAttribute, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> </DockPanel> </Canvas> |
Cabur - Sa 26.10.19 16:33
Doch, dass habe ich implementiert, aber irgendwie ist das nicht mit eingefügt worden.
C#-Quelltext
1: 2: 3: 4:
| public class MainWindowViewModel : BaseViewModel { } |
C#-Quelltext
1: 2: 3: 4:
| public class PageViewModel : BaseViewModel { } |
Th69 - So 27.10.19 06:44
Hast du es denn mal mit Visibility als Datentyp ausprobiert?
Cabur - Di 29.10.19 12:50
So ich habe jetzt folgendes probiert bzw. geändert:
MainWindowViewModel:
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| public class MainWindowViewModel : BaseViewModel { public NavigationService nav; public RelayCommand CmdOpenPage { get; private set; } public RelayCommand CmdOpenPanel { get; private set; }
public MainWindowViewModel() { OpenPanelAttribute = Visibility.Collapsed; CmdOpenPanel = new RelayCommand(OpenPanel); CmdOpenPage = new RelayCommand(OpenPage); }
private Enum openPanelAttribute; public Enum OpenPanelAttribute { get { return openPanelAttribute; } set { if (value != openPanelAttribute) { openPanelAttribute = value; OnPropertyChanged("OpenPanelAttribute"); } } }
private void OpenPage(object open) { nav.Navigate(new PageView()); }
private void OpenPanel(object open) { MessageBox.Show(Convert.ToString(OpenPanelAttribute), "", MessageBoxButton.OK); OpenPanelAttribute = Visibility.Visible; MessageBox.Show(Convert.ToString(OpenPanelAttribute), "", MessageBoxButton.OK); } } |
PageViewModel:
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:
| public class PageViewModel : BaseViewModel { public RelayCommand CmdOpenMainPanel;
public PageViewModel { CmdOpenMainPanel = new RelayCommand(OpenMainPanel); }
private void OpenMainPanel(object open) { private MainWindowViewModel mainWindow = new MainWindowViewModel(); mainWindow.OpenPanelAttribute = Visibility.Visible;
private MainWindowViewModel mainWindow = new MainWindowViewModel(); mainWindow.OpenPanel(open); } } |
In beiden Fällen wird zwar aus PageViewModel Visibility auf Visible gesetzt, aber das Panel wird nicht angezeigt. Wenn ich aber direkt aus dem MainWindowViewModel Visibility auf Visible setze, dann wird auch das Panel angezeigt.
Th69 - Di 29.10.19 15:43
So kann der Zugriff (in
OpenMainPanel) ja auch nicht klappen:
- was soll das
private dort (das kompiliert doch gar nicht)?
- du erzeugst dort ein
neues MainWindowViewModel, welches nichts mit der existierenden Instanz zu tun hat.
-> du mußt dem
PageViewModel die aktuelle
MainPageViewModel-Instanz (z.B. als Konstruktorparameter) übergeben oder noch besser ein Ereignis verwenden (s.a. meinen Artikel
Kommunikation von 2 Forms [
https://entwickler-ecke.de/topic_Kommunikation+von+2+Forms_117789.html] - primär zwar für WinForms geschrieben, aber die generelle Vorgehensweise gilt auch für WPF und MVVM).
PS: Wieso denn jetzt
Enum? Ich meinte explizit
C#-Quelltext
1: 2: 3: 4: 5:
| private Visibility openPanelAttribute; public Visibility OpenPanelAttribute { } |
Cabur - Di 05.11.19 23:33
Danke für deine Hilfe. Ich habe jetzt Enum in Visibility geändert. Jedoch stehe ich anscheinend mit dem Ereignis total auf dem Schlauch. Ich habe es in den letzten Tagen probiert, aber eine Lösung habe ich dafür nicht gefunden. Hast du mal einen Denkanstoß für mich, wie ich das mit einem Ereignis hinbekomme?
Th69 - Mi 06.11.19 10:08
Wenn du das mit dem Ereignis noch nicht hinbekommst, dann nimm die einfachere Möglichkeit und übergebe dem
PageViewModel die aktuelle
MainPageViewModel-Instanz (eine der beiden Klassen muß die andere kennen).
Wie und wo genau erstellst du denn diese Instanzen (im View-Codebehind oder per XAML oder ...)?
Wenn ich deinen Code richtig interpretiere, dann erzeugst du doch mittels
C#-Quelltext
1: 2: 3: 4:
| private void OpenPage(object open) { nav.Navigate(new PageView()); } |
die neue
Page. Du brauchst dort dann einfach im Konstruktor
this (d.h. die
MainPageViewModel-Instanz) übergeben und im
PageView(...)-Konstruktor diese Instanz dann an das
PageViewModel weiterreichen.
Bei dem Ereignis wäre es umgekehrt, so daß das (übergeordnete)
MainWindowViewModel das Ereignis bei dem
PageViewModel abonnieren würde.
PS: Nur damit du das Stichwort schon mal gehört hast - bei professionellen Programmen benutzt man häufig eine Technik namens "Inversion of Control" bzw. konkret
Dependency Injection [
https://de.wikipedia.org/wiki/Dependency_Injection].
Cabur - Do 07.11.19 22:15
Th69 hat folgendes geschrieben : |
Wie und wo genau erstellst du denn diese Instanzen (im View-Codebehind oder per XAML oder ...)? |
Ich erstelle die Instanz per XAML
XML-Daten
1: 2: 3:
| <Page.DataContext> <viewmodel:PageViewModel/> </Page.DataContext> |
Th69 - Fr 08.11.19 07:23
Dann wirst du das wohl ändern müssen, so daß du Zugriff darauf bekommst (also in den Codebehind einfügen).
Die verschiedenen Möglichkeiten sind z.B. in
Different Ways to Bind WPF View And View Model [
https://www.dotnetforall.com/different-ways-bind-view-view-model/] (wenn auch auf englisch, aber der Source-Code sollte selbsterklärend sein) erklärt.
Alternativ könntest du auch in deinem
MainPageViewModel schon das
PageViewModel erzeugen (s. 2. Ansatz "View Model First Approach" in obigen Artikel) und übergibst das dann an die
PageView als Parameter (dies ist dann quasi schon der "Dependency Injection"-Ansatz):
C#-Quelltext
1: 2: 3: 4: 5: 6:
| public PageView(PageViewModel pageViewModel) { InitializeComponent();
DataContext = pageViewModel; } |
Cabur - Do 14.11.19 11:40
Vielen Dank, mit deiner Hilfe konnte ich mein Problem endlich lösen. Vielen, vielen Dank!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!