View an ViewModel mittels DataTemplate binden (kein parameterlose Konstruktor)

Dey

Banned
Registriert
Mai 2005
Beiträge
1.925
Hi.

Nachdem ich dank Eurer Hilfe einige ViewModels per DataTepmlate erfolgreich an Views gebunden habe, bin ich jetzt auf eine Ausnahme gestoßen, bei der das nicht ohne weiteres möglich.

Konkret habe ich ein TreeViewUserControl und ein TreeViewItemViewModel. Das TreeViewItemViewModel erwartet im Parameter ein Xml-Dokument. Solange ich das ViewModel in der Codebehind-Datei der View instanziiere und zuweise, funktioniert alles.

Ich möchte jedoch gerne das ViewModel per DataBinding an die View binden. Der übliche Weg über ein DataTemplate funktioniert nicht, weil das ViewModel keinen parameterlosen Konstruktor besitzt.

Da das TreeViewItemViewModel jedoch als Property in meinem MainWindowViewModel definiert ist, besteht vielleicht die Möglichkeit, das TreeViewUserControl an dieses zu binden.

Ich hoffe, dass ihr mir dabei helfen könnt, die Property an das TreeViewUserControl zu binden.

Meine Struktur sieht folgendermaßen aus:

MainWindow > TreeViewUserControl
MainWindowViewModel > TreeViewItemViewModel


Die folgende Zuweisung funktioniert leider nicht:

PHP:
 <TreeView.DataContext=
"{Binding DataContext.XmlTreeViewItemViewModel, 
RelativeSource={RelativeSource AncestorType={x:Type view:MainWindow}, Mode=FindAncestor}}">
</TreeView.DataContext>
 
Entweder versteh ich nicht, was du machen willst oder du drückst dich komisch aus :D

MainWindow.DataContext = MainWindowViewModel, richtig?

In dem Fenster MainWindow gibt es nun eine UserControl TreeView, dessen DataContext du an ein weiteres ViewModel (TreeViewItemViewModel) binden möchtest? Zufälligerweise veröffentlichst du (über ein Property in MainWindowViewModel) das TreeViewItemViewModel?

Also, wenn ich richtig rate, dann möchtest du folgendes tun
Code:
<TreeView DataContext={Binding TreeViewItemViewModelPropertyName} />

Aber wie gesagt, blick bei deinem Post nicht durch, sorry ;)
Btw. wer hat dir eingeredet, dass man ViewModel nur über DataTemplates binden sollte?
 
Du hast es schon fast richtig verstanden. Ich habe jedoch kein TreeView-Control in dem MainWindow, sondern ein eigenständiges UserControl mit dem Namen TreeViewUserControl. Dieses UserControl erzeuge ich in der MainWindow-View auf folgende Weise:

PHP:
<view:TreeViewUserControl  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,3,0"></view:TreeViewUserControl>

Der vorgeschlagene Weg durch Zuweisung der Property an die DataContext-Eigenschaft funktioniert hierbei leider nicht. Möglicherweise muss ich zunächst etwas anderes tun (ein DataTemplate definieren oder so).

Leider weiß ich nicht so genau was :D Dazu bin ich noch nicht fortgeschritten genung in WPF.
 
Kannst du kurz erklären, was genau du bezwecken möchtest? Evtl. kann man dir dann besser helfen. Momentan stolper ich noch über den Gedanken, dass du ein ViewModel an ein Control binden möchtest ;)
 
Inwiefern stolperst du über diesen Gedanken?

Um die Geschäftslogik in übersichtliche Blöcke zu trennen, lagere ich zusammengehörige Elemente in separate UserControls aus. Diese UserControls erhalten eigene ViewModels, sodass ich nicht die gesamte Logik in einer Klasse habe, sondern eine nach Verantwortlichkeit organisierte Struktur.

Beispiel: Ich könnte eine Suche für TreeViewItems implementieren und hätte nur das jeweilige ViewModel des UserControls erweitern müssen. Der restliche Code bleibt unberührt. Gleichzeitig erhalte ich die Möglichkeit, dass UserControl in anderen Programmen zu nutzen (die Schnittstellen sind durch das ViewModel definiert und erlauben es, dass spezifische Ableitungen erzeugt werden können, z.B. XmlNodeItem).

Auf diese Weise entstehen Hierarchien und UserControls stellen Unterelemente meines MainWindows dar Für die anderen UserControls kann ich das Binding per DataTemplate in den Ressourcen deklarieren:

PHP:
<viewModel:BookmarkUserControlViewModel x:Key="BookmarkUserControlViewModel"/>
    
    <DataTemplate DataType="{x:Type viewModel:BookmarkUserControlViewModel}">
        <view:BookmarkUserControl/>
    </DataTemplate>

Dies funktioniert für das TreeViewItemViewModel nicht, da dieses keinen parameterlosen Konstruktor besitzt. Jetzt sehe ich nur noch die Möglichkeit, das ViewModel in der Codebehind-Datei zu instanziieren. Dies würde jedoch meine Struktur verletzen, da das TreeViewItemViewModel im MainWindowViewModel instanziiert werden sollte und es das UserControl nicht kennen darf.
 
Was ist mit dem ViewModelLocator(Pattern)?

Was spricht gegen das Binden im VM per Property?

Code:
    <Window.Resources>
        <DataTemplate DataType="{x:Type viewModel:CustomViewModel}">
            <view:CustomControl />
        </DataTemplate>
    </Window.Resources>
    
    <Grid>
        <ContentControl Content="{Binding Workspace}" />
    </Grid>

Code:
// im CodeBehind

Workspace = new CustomViewModel("Test","Test2");

Dadurch kann das ViewModels soviel KonstrukturParameter enthalten wie Du es möchtest.
 
Dey schrieb:
Um die Geschäftslogik in übersichtliche Blöcke zu trennen, lagere ich zusammengehörige Elemente in separate UserControls aus. Diese UserControls erhalten eigene ViewModels, sodass ich nicht die gesamte Logik in einer Klasse habe, sondern eine nach Verantwortlichkeit organisierte Struktur.

Was du eigentlich tust, ist die Verlagerung von View<->CodeBehind zu Control<->ViewModel. Du tausch eine Abhängigkeit gegen eine Andere. Dies ist nicht der Sinn von MVVM. Es ist nur eine Vermutung meinerseits, aber dein UserControl funktioniert nicht ohne das entsprechende ViewModel. Lieg ich da richtig?

Dey schrieb:
Beispiel: Ich könnte eine Suche für TreeViewItems implementieren und hätte nur das jeweilige ViewModel des UserControls erweitern müssen. Der restliche Code bleibt unberührt. Gleichzeitig erhalte ich die Möglichkeit, dass UserControl in anderen Programmen zu nutzen (die Schnittstellen sind durch das ViewModel definiert und erlauben es, dass spezifische Ableitungen erzeugt werden können, z.B. XmlNodeItem).

"Die Schnittstellen sind durch das ViewModel definiert". Vermutlich weißt du, was IoC bedeutet. Ich glaube, du hast eben IoD geschaffen - Inverse of Design :)

Code:
<UserControl x:Class="MyControl">
  <Grid Width="{Binding Width}" Height="{Binding Height}" />
</UserControl>

Obiger Code wäre so ein Negativbeispiel. Ohne entsprechendes ViewModel, dass die Properties "Width" und "Height" bereitstellt, wird dieses Control niemals angeizeigt werden.

Um es noch deutlicher zu machen
Code:
<local:MyControl Width="100" Height="50" />
wäre nicht möglich.

Dey schrieb:
Auf diese Weise entstehen Hierarchien und UserControls stellen Unterelemente meines MainWindows dar Für die anderen UserControls kann ich das Binding per DataTemplate in den Ressourcen deklarieren:

PHP:
<viewModel:BookmarkUserControlViewModel x:Key="BookmarkUserControlViewModel"/>
    
    <DataTemplate DataType="{x:Type viewModel:BookmarkUserControlViewModel}">
        <view:BookmarkUserControl/>
    </DataTemplate>

Dies funktioniert für das TreeViewItemViewModel nicht, da dieses keinen parameterlosen Konstruktor besitzt. Jetzt sehe ich nur noch die Möglichkeit, das ViewModel in der Codebehind-Datei zu instanziieren. Dies würde jedoch meine Struktur verletzen, da das TreeViewItemViewModel im MainWindowViewModel instanziiert werden sollte und es das UserControl nicht kennen darf.

Dann instanziere es doch auch da. Wo ist dein Problem? Der Weg über Templates, oft zitiert/kopiert, aber noch öfter falsch verstanden, ist nur einer von Vielen. Im Grunde ist ein Type-Template nichts anderes als minimales IoC - man überlässt WPFs Dependency-System die Auflösung eines Typens. Code != schlechter Stil!

Es heißt "loose coupling" nicht "complete decoupling". Verabschiede dich von dem Gedanken Codebehind == No-Go! Dein Control ist teil der Klasse MainWindow, d.h. sie sollte auch alle nötigen Infos aus dem entsprechendem ViewModel erlagen können. Benutz DependencyProperties in deinem UserControl, um per Binding an die nötigen Infos kommen zu können.

Z.B.
Code:
public partial class TreeViewControl : UserControl
{
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register( "ItemsSource", typeof ( ICollection ), typeof ( TreeViewControl ),
                                                    new PropertyMetadata( default(ICollection) ) );

    public ICollection ItemsSource
    {
        get { return (ICollection) GetValue( ItemsSourceProperty ); }
        set { SetValue( ItemsSourceProperty, value ); }
    }
}

Code:
public class ViewModel
{
    public ObservableCollection<Foo> Items { get; set; }
}

Code:
<local:TreeViewControl ItemsSource="{Binding Items}" />
 
Zuletzt bearbeitet:
lbm1305 schrieb:
Was ist mit dem ViewModelLocator(Pattern)?

Was spricht gegen das Binden im VM per Property?

Code:
    <Window.Resources>
        <DataTemplate DataType="{x:Type viewModel:CustomViewModel}">
            <view:CustomControl />
        </DataTemplate>
    </Window.Resources>
    
    <Grid>
        <ContentControl Content="{Binding Workspace}" />
    </Grid>

Code:
// im CodeBehind

Workspace = new CustomViewModel("Test","Test2");

Dadurch kann das ViewModels soviel KonstrukturParameter enthalten wie Du es möchtest.

Klingt nicht schlecht. Allerdings ist das CustomControlViewModel als Property im MainWindowViewModel definiert. Das CustomControlViewModel sollte sich dort auch weiterhin befinden, damit das MainWindowViewModel die Properties des CustomControlViewModels mit Werten belegen kann. Hast du eine Idee, wie ich in diesem Fall das CustomControlViewModel ans CustomControl binden kann?
 
Dey schrieb:
Klingt nicht schlecht. Allerdings ist das CustomControlViewModel als Property im MainWindowViewModel definiert. Das CustomControlViewModel sollte sich dort auch weiterhin befinden, damit das MainWindowViewModel die Properties des CustomControlViewModels mit Werten belegen kann. Hast du eine Idee, wie ich in diesem Fall das CustomControlViewModel ans CustomControl binden kann?

Vielleicht ignorierst du mich ja bewusst, keine Ahnung. Egal, ich versuch es nun nochmal - etwas detaillierter. Um es von vorherein klar zu machen, es wird auf das heinauslaufen, was ich bereits in meinem ersten Post hier geschrieben habe. Allerdings lass ich diesmal eine Antwort wie "Der vorgeschlagene Weg durch Zuweisung der Property an die DataContext-Eigenschaft funktioniert hierbei leider nicht." nicht mehr gelten.

Dein Markup schaut so aus:

- MainWindow
- UserControl​

Ein Test Projekt von mir, um es zu verdeutlichen. Insgesamt sollen drei UserControls im Fenster zu sehen sein. Das erste Control wird explizit gebunden, das Zweite wird über ein Template eingebunden und schließlich das Dritte implizit, d.h. es erbt den DataContext von der Klasse MainWindow

Code:
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow">

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:UserControlViewModel}">
            <local:MyUserControl />
        </DataTemplate>
    </Window.Resources>

    <Grid Width="600" Height="400">
        <local:MyUserControl x:Name="myFirstControl" 
                             VerticalAlignment="Top"
                             HorizontalAlignment="Left"
                             Margin="20"
                             DataContext="{Binding UserControlViewModel}" />

        <ContentControl Content="{Binding TemplatedUserControlViewModel}" />
        
        <local:MyUserControl x:Name="mySecondControl" 
                             VerticalAlignment="Bottom"
                             HorizontalAlignment="Right"
                             Margin="20" />
    </Grid>
</Window>

MyUserControl entspricht dabei deiner TreeViewControl. Das Markup für MyUserControl:
Code:
<UserControl x:Class="WpfApplication1.MyUserControl"
             x:Name="MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Width="{Binding Path=Width}" Height="{Binding Path=Height}" Background="{Binding Path=Background}" />
</UserControl>

Die beiden CodeBehind-Dateien:

MainWindow.xaml.cs
Code:
namespace WpfApplication1
{
    using System.Windows;

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

MyUserControl.xaml.cs
Code:
namespace WpfApplication1
{
    using System.Windows.Controls;

    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    }
}

Jetzt kommen die beiden ViewModel - MainWindowViewModel und UserControlViewModel.
Letzteres stellt Properties für Höhe, Breite und Hintergrundfarbe zur verfügung. Das MainWindowViewModel ist nahezu identisch, hat aber zwei weitere Properties. Diese beiden Properties stellen jeweils ein UserControlViewModel zur Verfügung. Eins davon wird explizit gebunden, das andere view ViewModelLocator geladen.
Lenke deine Aufmerksamkeit auf die jeweiligen Konstruktoren. MainWindowViewModel benutzt einen Standard-Konstruktor, während UserControlViewModel drei Parameter verlangt.

UserControlViewModel.cs
Code:
namespace WpfApplication1
{
    using System.Windows.Media;

    public class UserControlViewModel : ViewModelBase
    {
        private Brush _backgroundBrush;

        private double _height;

        private double _width;

        public UserControlViewModel( double width, double height, Brush background)
        {
            Background = background;
            Height = height;
            Width = width;
        }

        public double Width
        {
            get { return _width; }
            set { SetProperty( ref _width, value, "Width" ); }
        }

        public double Height
        {
            get { return _height; }
            set { SetProperty( ref _height, value, "Height" ); }
        }

        public Brush Background
        {
            get { return _backgroundBrush; }
            set { SetProperty( ref _backgroundBrush, value, "Background" ); }
        }
    }
}

MainWindowViewModel.cs
Code:
namespace WpfApplication1
{
    using System.Windows.Media;

    public class MainWindowViewModel : ViewModelBase
    {
        private Brush _backgroundBrush;

        private double _height;

        private double _width;

        public MainWindowViewModel()
        {
            UserControlViewModel = new UserControlViewModel( 100, 100, new SolidColorBrush( Colors.Red ) );

            TemplatedUserControlViewModel = new UserControlViewModel( 100, 100, new SolidColorBrush( Colors.Green ) );

            Background = new SolidColorBrush( Colors.Yellow );
            Width = 100;
            Height = 100;
        }

        public UserControlViewModel UserControlViewModel { get; private set; }

        public UserControlViewModel TemplatedUserControlViewModel { get; private set; }

        public Brush Background
        {
            get { return _backgroundBrush; }
            set { SetProperty( ref _backgroundBrush, value, "Background" ); }
        }

        public double Height
        {
            get { return _height; }
            set { SetProperty( ref _height, value, "Height" ); }
        }

        public double Width
        {
            get { return _width; }
            set { SetProperty( ref _width, value, "Width" ); }
        }

    }
}

Der Vollständigkeithalber hier noch die Klasse ViewModelBase.

ViewModelBase.cs
Code:
namespace WpfApplication1
{
    using System.ComponentModel;

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if ( handler != null ) handler( this, new PropertyChangedEventArgs( propertyName ) );
        }

        protected bool SetProperty<T>(ref T storage, T value, string propertyName)
        {
            if ( Equals( storage, value ) ) return false;

            storage = value;
            RaisePropertyChanged( propertyName );
            return true;
        }
    }
}

Da du das UserControlViewModel über das MainWindowViewModel veröffentlichst, musst du es auch dort initialisieren. Alles andere endet in Spaghetti-Code.

Damit das ganze nun auch läuft hier noch die App.xaml und App.xaml.cs. Alternativ kannst du hier natürlich auch wieder das ViewModelLocator-Pattern nutzen.

App.xaml
Code:
<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

App.xaml.cs
Code:
namespace WpfApplication1
{
    using System.Windows;

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            MainWindowViewModel vm = new MainWindowViewModel();
            MainWindow mw = new MainWindow {DataContext = vm};
            mw.Show();
        }
    }
}

Schau dir den Screenshot an, wie das ganze Aussieht.
Wenn du mir jetzt immer noch sagen möchtest, dass es nicht geht, dann diesmal bitte mit Begründung, was bei dir schief läuft.
 

Anhänge

  • beispiel.png
    beispiel.png
    5,8 KB · Aufrufe: 161
holy schrieb:
Was du eigentlich tust, ist die Verlagerung von View<->CodeBehind zu Control<->ViewModel. Du tausch eine Abhängigkeit gegen eine Andere. Dies ist nicht der Sinn von MVVM. Es ist nur eine Vermutung meinerseits, aber dein UserControl funktioniert nicht ohne das entsprechende ViewModel. Lieg ich da richtig?

Ja, aber das ist doch Sinn von MVVM. Das ViewModel soll die View nicht kennen. Erst dadurch ist ein sauberes Unit-Testing möglich und die View kann nach Belieben ausgetauscht werden.

Andersherum darf die View das ViewModel kennen, muss es aber nicht zwingend. Wenn man eine möglichst lose Kopplung erreichen will, sollte die Codebehind-Datei der View weitestgehend leer bleiben.

Meine View ließe sich wohl ohne ViewModel anzeigen, aber da das ViewModel die ganze Logik definiert, würde die Applikation ohne ViewModel nichts weiter tun.[/QUOTE]

holy schrieb:
Dann instanziere es doch auch da. Wo ist dein Problem? Der Weg über Templates, oft zitiert/kopiert, aber noch öfter falsch verstanden, ist nur einer von Vielen. Im Grunde ist ein Type-Template nichts anderes als minimales IoC - man überlässt WPFs Dependency-System die Auflösung eines Typens. Code != schlechter Stil!

Es heißt "loose coupling" nicht "complete decoupling". Verabschiede dich von dem Gedanken Codebehind == No-Go! Dein Control ist teil der Klasse MainWindow, d.h. sie sollte auch alle nötigen Infos aus dem entsprechendem ViewModel erlagen können. Benutz DependencyProperties in deinem UserControl, um per Binding an die nötigen Infos kommen zu können.

Das ist nicht ohne weiteres möglich. Das TreeViewItemViewModel muss weiterhin im MainWindowViewModel instanziiert werden. Da das MainWindowViewModel die Views nicht kennt, sehe ich auch keine Möglichkeit, das TreeViewItemViewModel auszulagern.

Meine Logik sieht folgendermaßen aus:

1. Das MainWindowViewModel erzeugt ein XmlDocument
2. Das MainWindowViewModel erzeugt das TreeViewItemViewModel (XmlDocument wird im Konstruktor übergeben)
3. Das TreeViewItemViewModel initialisiert während der Instanziierung seine Children

Wenn das TreeViewControl an das TreeViewItemViewModel gebunden wäre, würde es jetzt die neuen Werte des ViewModels anzeigen.

Alle Wege, die über die Codebehind-Datei des TreeViewControls führen, funktionieren nicht, da mein MainWindowViewModel das TreeViewControl nicht kennt.

Der Weg muss also wohl über den DataContext des MainWindows (MainWindowViewModel) führen.

holy schrieb:
Code:
public partial class TreeViewControl : UserControl
{
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register( "ItemsSource", typeof ( ICollection ), typeof ( TreeViewControl ),
                                                    new PropertyMetadata( default(ICollection) ) );

    public ICollection ItemsSource
    {
        get { return (ICollection) GetValue( ItemsSourceProperty ); }
        set { SetValue( ItemsSourceProperty, value ); }
    }
}

Code:
public class ViewModel
{
    public ObservableCollection<Foo> Items { get; set; }
}

Code:
<local:TreeViewControl ItemsSource="{Binding Items}" />

Das werde ich mal ausprobieren.

Update:

Hallo holy, ich ignoriere dich auf keinen Fall. Ich bin dir dankbar für deine Anregungen und Tipps. Und ich suche Wege, deine Ratschläge umzusetzen. Leider ist mein WPF-Wissen noch lückenhaft, sodass ich etwas Zeit zum Verdauen brauche ;-)
 
Zuletzt bearbeitet:
Dey schrieb:
Ja, aber das ist doch Sinn von MVVM. Das ViewModel soll die View nicht kennen. Erst dadurch ist ein sauberes Unit-Testing möglich und die View kann nach Belieben ausgetauscht werden.

Andersherum darf die View das ViewModel kennen, muss es aber nicht zwingend. Wenn man eine möglichst lose Kopplung erreichen will, sollte die Codebehind-Datei der View weitestgehend leer bleiben.

Meine View ließe sich wohl ohne ViewModel anzeigen, aber da das ViewModel die ganze Logik definiert, würde die Applikation ohne ViewModel nichts weiter tun.

Du hast mich da falsch verstanden. Schau dir mal das Beispiel in meinem vorherigen Post an. Das UserControl MyUserControl ist so ein Control, dass sich nur mit dem entsprechendem ViewModel nutzen lässt.
Code:
<local:MyUserControl Width="100" Height="100" Background="Green" />
kannst du zwar schreiben, aber alles was du damit bewirkst ist ein 100x100px großes, leeres Grid anzuzeigen.

Dey schrieb:
Das ist nicht ohne weiteres möglich. Das TreeViewItemViewModel muss weiterhin im MainWindowViewModel instanziiert werden. Da das MainWindowViewModel die Views nicht kennt, sehe ich auch keine Möglichkeit, das TreeViewItemViewModel auszulagern.

Mit meinem "Dann instanziere es doch auch da." habe ich mich auf dein "Dies würde jedoch meine Struktur verletzen, da das TreeViewItemViewModel im MainWindowViewModel instanziiert werden sollte und es das UserControl nicht kennen darf." bezogen ;)

Dey schrieb:
Meine Logik sieht folgendermaßen aus:

1. Das MainWindowViewModel erzeugt ein XmlDocument
2. Das MainWindowViewModel erzeugt das TreeViewItemViewModel (XmlDocument wird im Konstruktor übergeben)
3. Das TreeViewItemViewModel initialisiert während der Instanziierung seine Children

Wenn das TreeViewControl an das TreeViewItemViewModel gebunden wäre, würde es jetzt die neuen Werte des ViewModels anzeigen.

Alle Wege, die über die Codebehind-Datei des TreeViewControls führen, funktionieren nicht, da mein MainWindowViewModel das TreeViewControl nicht kennt.

Der Weg muss also wohl über den DataContext des MainWindows (MainWindowViewModel) führen.

Vgl. Beispiel oben. Die DependencyProperties brauchst du nur, wenn dein UserControl irgend ein neues Property bereitstellt, dass du per DataBinding füllen möchtest.
Ergänzung ()

Dey schrieb:
Hallo holy, ich ignoriere dich auf keinen Fall.

Nimm das nicht allzu ernst was ich da schreibe :)
 
@holy:

Klasse! Deine Antwort lässt keine Wünsche mehr offen.

Ich werde mich sofort an den Code machen.

Jetzt habe ich keine Zweifel mehr, dass es möglich ist :):):)

Vielen Dank.
 
Ich habe eine gute und eine schlechte Nachricht:

In meinem Hauptprojekt klappt es einfach nicht. Als ich kurz vorm Verzweifeln war, habe ich ein neues Projekt angelegt. Und siehe da... dein Code funzt natürlich einwandfrei.

Die Werte aus der Xml-Datei werden bereits im Designer korrekt angezeigt. Sehr erfreulich :)

Jetzt muss ich nur noch herausfinden, warum es im anderen Projekt nicht funkioniert. Noch habe ich keine Idee, woran es scheitert.

Ich halte dich aber auf dem Laufenden.

Ich danke dir! ;)
 
Wenn du dein Projekt hier anhängen kannst/darfst, könnte man dir bei der Fehlersuche helfen.
 
Dey schrieb:
Klingt nicht schlecht. Allerdings ist das CustomControlViewModel als Property im MainWindowViewModel definiert. Das CustomControlViewModel sollte sich dort auch weiterhin befinden, damit das MainWindowViewModel die Properties des CustomControlViewModels mit Werten belegen kann. Hast du eine Idee, wie ich in diesem Fall das CustomControlViewModel ans CustomControl binden kann?

Hat es einen Grund, warum die ViewModels als Property angelegt werden?
Warum übergibst Du die Instanzen des jeweiligen ViewModels nicht im Konstruktor des MainWindowViewModels?
 
lbm1305 schrieb:
Hat es einen Grund, warum die ViewModels als Property angelegt werden?
Warum übergibst Du die Instanzen des jeweiligen ViewModels nicht im Konstruktor des MainWindowViewModels?

Ja. Ich habe die ViewModels als Property definiert, damit sie im MainWindow-ViewModel direkt angesprochen werden können. Ein kleines Beispiel: Ich habe eine Funktion, um eine XML-Datei mit der Serienbrieffunktion von Word zu verknüpfen. Die Funktion wird durch das Command "MailMergeCommand" bereitgestellt.

Damit das MainWindowViewModel keine Gott-Klasse wird, habe ich die Logik für das "MailMergeCommand" in ein eigenes ViewModel verschoben. Auch auf View-Seite habe ich eine derartige Hierarchie. Für das "MailMergeCommand" habe ich ein UserControl "MailMergeControl" definiert, welches User-Eingaben erwartet. Durch DataBinding werden diese Einstellungen an das speziellere ViewModel übergeben, statt an das MainWindow-ViewModel.

Dennoch ist das spezielle MailMergeControlViewModel nicht ganz eigenständig, da es zum Beispiel das aktive Word-Dokument vom MainWindowViewModel erhält. Zusammenfassend würde ich folgende Vorteile aufführen:

- klare logische Einheiten, welche die Verantwortlichkeiten sauber trennen
- saubere Unit Tests, da die Einheiten kleiner sind und von weniger Faktoren beeinflusst werden
- höhere Wiederverwendbarkeit

Ich denke,dass man als Entwickler ab einer bestimmten Größe des Projekts gezwungen wird, eine derartige Verschachtelung der Logik durchzuführen.

Oder machen es Entwickler anders?
 
Dey schrieb:
Hast du eine Idee, wie ich in diesem Fall das CustomControlViewModel ans CustomControl binden kann?

Wenn Du das CustomViewModel dem Property Workspace zuweist, wird durch das Template automatisch ein Binding mit dem View hergestellt. Wichtig ist eben dabei, dass die Zuweisung per Template erfolgt.
 

Ähnliche Themen

Zurück
Oben