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.