Benutzer mit den meisten Antworten
WPF-MVVM Mehrere ViewModels in einem Window binden

Frage
-
Hi,
ich hatte hier folgenden Thread Datenbindung zwischen Child und Parent in einer Observable Collection (eigene Klasse), welcher von Koopakiller beantwortet wurde.
Dabei wurde eine Klasse namens MyItem erstellt. Das ist im Endeffekt eine Observable Collection von MyItem welche den DataContext vom Window belegt mit der kleinen Zeile:
this.DataContext = this;
Jetzt will ich später aber, wegen dutzender Datenbankabfragen die gleichzeitig stattfinden, eine ProgressBar mit einbinden. Diese benötigt aber ViewModels, soweit ich das verstanden habe. Um ein ViewModel einzubinden soll man (zumindest laut allen Erklärungen die ich fand)
DataContext = new MyViewModel();
setzen.
Meine Frage wäre jetzt: Wie muss ich hier vorgehen? Wie bekomme ich MyItem in das ViewModel oder wie binde ich beides in den DataContext?
Antworten
-
Hi,
jedes FrameworkElement hat eine Eigenschaft DataContext. Ist die in einem Element nicht gesetzt, wird die des übergeordneten Elementes geerbt.
Deswegen setzt man oftmals den DataContext für ein Window und vererbt damit an alle Element, wie z.B. einen ProgressBar den DataContext.
Hat man jetzt, so wie in deinem Fall, die Anforderung in einem Window ein oder mehrere Elemente einem anderen DataContext zuzuweisen, so setzt man den für das entsprechende Element neu.
Wenn du einen ViewModelLocator, wie z.B. aus MVVMLight verwendest, kann dein XAML dann wie folgt aussehen:
<ProgressBar DataContext="{Binding ProgressBarViewModel, Source={StaticResource Locator}}">
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:07
- Tag als Antwort aufgehoben Marcel Gpunkt Donnerstag, 6. November 2014 13:14
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:59
-
Das geht natürlich auch:
<Window x:Class.... xmlns:vms="clr-namespace:DeineApp.ViewModel" .... /> ... <Window.DataContext> <vms:MainViewModel /> </Window.DataContext> ... <ProgressBar> <ProgressBar.DataContext> <vms:ProgessBarViewModel /> </ProgressBar.DataContext> </ProgressBar>
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:06
- Tag als Antwort aufgehoben Marcel Gpunkt Donnerstag, 6. November 2014 13:14
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:58
-
Ändere mal
xmlns:vms="clr-namespace:ASAVideowand.ProgressBarViewModel"
inxmlns:vms="clr-namespace:ASAVideowand"
Bringt das was ? Die Namespace-Deklaration braucht ja nur den Namespace selber und nicht das ViewModel, ads benutzt wird.
Claudius
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:58
Alle Antworten
-
Hallo Taldrit,
ein Weg, das zu machen, wäre eine Klasse zu erstellen, die als Repräsentierung des DataContexts gilt und deren Properties als die gewünschten ViewModels zu deklarieren.
Bsp:
public class DataContextKlasse : INotifyPropertyChanged { public ViewModel1 VM1 {get; set;} public ViewModel2 VM2 {get; set;} } DataContextKlasse dataContext = new DataContextKlasse (); dataContext.VM1 = new ViewModel1 (); dataContext.VM2 = new ViewModel2 (); DataContext = dataContext;
Dann kannst du einen 'globalen' DataContext erstellen, über dessen Properties zugegriffen und geupdated werden kann.
Ist wie gesagt, ein Lösungsweg, den ich auch mal genutzt habe, da man eben nur einen DataContext festlegen kann.
Gruß Claudius
- Als Antwort vorgeschlagen Aleksander Chalabashiev Donnerstag, 6. November 2014 10:46
-
Hi,
jedes FrameworkElement hat eine Eigenschaft DataContext. Ist die in einem Element nicht gesetzt, wird die des übergeordneten Elementes geerbt.
Deswegen setzt man oftmals den DataContext für ein Window und vererbt damit an alle Element, wie z.B. einen ProgressBar den DataContext.
Hat man jetzt, so wie in deinem Fall, die Anforderung in einem Window ein oder mehrere Elemente einem anderen DataContext zuzuweisen, so setzt man den für das entsprechende Element neu.
Wenn du einen ViewModelLocator, wie z.B. aus MVVMLight verwendest, kann dein XAML dann wie folgt aussehen:
<ProgressBar DataContext="{Binding ProgressBarViewModel, Source={StaticResource Locator}}">
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:07
- Tag als Antwort aufgehoben Marcel Gpunkt Donnerstag, 6. November 2014 13:14
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:59
-
Hi Claudius,
wie in meiner obigen Antwort schon geschrieben, kannst du im XAML für jedes Element den DataContext setzen. Damit kannst du dir das Erstellen deiner DataContextKlasse sparen.
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net -
Ja. Deine Idee funktionieren natürlich auch.
Viele Wege führen nach Rom :)Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net -
Wenn du einen ViewModelLocator, wie z.B. aus MVVMLight verwendest, kann dein XAML dann wie folgt aussehen:
Diese Idee hört sich schon toll an, nur kann ich mit einem Locator nicht viel anfangen. Kann ich auch irgendwie einfach die Datei, bzw. das ViewModel als StaticRessource angeben?<ProgressBar DataContext="{Binding ProgressBarViewModel, Source={StaticResource Locator}}">
-
Das geht natürlich auch:
<Window x:Class.... xmlns:vms="clr-namespace:DeineApp.ViewModel" .... /> ... <Window.DataContext> <vms:MainViewModel /> </Window.DataContext> ... <ProgressBar> <ProgressBar.DataContext> <vms:ProgessBarViewModel /> </ProgressBar.DataContext> </ProgressBar>
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:06
- Tag als Antwort aufgehoben Marcel Gpunkt Donnerstag, 6. November 2014 13:14
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:58
-
Ok, ich versuch es jetzt nochmal zusammenzufassen:
Mein XAML:
<Window x:Class="WpfVideowand.AdminConsole" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Converter="clr-namespace:WpfVideowand" xmlns:vms="clr-namespace:ASAVideowand.ProgressBarViewModel" Title="AdminConsole" Name="AdminConsoleWindow" WindowStartupLocation="Manual" Top="0" Left="0" Loaded="AdminConsole_Loaded" SizeToContent="WidthAndHeight" MaxHeight="1080" MaxWidth="1920" Closing="Window_Closing" WindowStyle="ThreeDBorderWindow" ResizeMode="CanMinimize">
...
<ProgressBar HorizontalAlignment="Left" VerticalAlignment="Top" Height="25" Width="760" Name="MyProgressBar"
Value="{Binding ProgressValue}" Minimum="{Binding MinValue}" Maximum="{Binding MaxValue}">
<ProgressBar.DataContext>
<vms:ProgressBarViewModel/>
</ProgressBar.DataContext>
</ProgressBar>Mein Code-Behind:
namespace ASAVideowand.ProgressBarViewModel { class ProgressBarViewModel : INotifyPropertyChanged { private int _progressValue = 0; private int _maxValue = 100; private int _minValue = 0; public int ProgressValue { get { return _progressValue; } set { _progressValue = value; OnPropertyChanged(); } } public int MaxValue { get { return _maxValue; } set { _maxValue = value; OnPropertyChanged(); } } public int MinValue { get { return _minValue; } set { _minValue = value; OnPropertyChanged(); } } public void RaiseValue(int raiseValue = 1) { ProgressValue += raiseValue; } public void SetMaximum(int maxValue) { MaxValue = maxValue; } public void SetMinimum(int minValue) { MinValue = minValue; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } } }
Ich bekomme jetzt nur die Meldung dass der Name ProgressBarViewModel im Namespace ASAVideowand.ProgressBarViewModel nicht vorhanden wäre...
Was habe ich vergessen?
-
Sieht auf den ersten Blick ok aus. Bis auf die Tatsache, dass der Namespace genauso heißt, wie dein ViewModel. Das könntest du mal ändern. Vielleicht verhaspelt sich WPF deswegen.
Nur am Rande: Dein ViewModel ist nicht CodeBehind ;)
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net -
Ich habs geändert, bringt aber leider nichts.
Das Lustige ist, dass, wenn ich "<vms:" eingebe, mir VS sogar vorschlägt "ProgressBarViewModel" zu nutzen.
Da muss ja noch irgendwas an meinem ViewModel falsch sein, oder?
p.s.: Es fehlte das public vor dem class ProgressBarViewModel... aber eine Änderung half auch nicht weiter.- Bearbeitet Marcel Gpunkt Donnerstag, 6. November 2014 13:42
-
Pack mal ein public vor class ProgressBarViewModel
Andreas Richter
Softwareentwickler und -architekt
http://www.anrichter.net -
Ändere mal
xmlns:vms="clr-namespace:ASAVideowand.ProgressBarViewModel"
inxmlns:vms="clr-namespace:ASAVideowand"
Bringt das was ? Die Namespace-Deklaration braucht ja nur den Namespace selber und nicht das ViewModel, ads benutzt wird.
Claudius
- Als Antwort markiert Marcel Gpunkt Donnerstag, 6. November 2014 13:58