I have a MainWindow containing a UserControl, both implemented in MVVM-pattern. The MainWindowVM has properties that I want to bind to properties in the UserControl1VM. But this doesn't work.
Here's some code (the viewmodels use some kind of mvvm-framework that implement the INotifyPropertyChanged in a ViewModelBase-class but that's hopefully no problem):
MainWindow.xaml:
<Window x:Class="DPandMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DPandMVVM"
Title="MainWindow" Height="300" Width="300">
<Grid>
<local:UserControl1 TextInControl="{Binding Text}" />
</Grid>
</Window>
CodeBehind MainWindow.xaml.cs:
using System.Windows;
namespace DPandMVVM
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowVM();
}
}
}
MainWindow-ViewModel MainWindowVM.cs:
namespace DPandMVVM
{
public class MainWindowVM : ViewModelBase
{
private string _text;
public string Text { get { return _text; } }
public MainWindowVM()
{
_text = "Text from MainWindowVM";
}
}
}
And here the UserControl1.xaml:
<UserControl x:Class="DPandMVVM.UserControl1"
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>
<TextBlock Text="{Binding TextInTextBlock}" />
</Grid>
</UserControl>
The Codebehind UserControl1.xaml.cs:
using System.Windows.Controls;
namespace DPandMVVM
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
DataContext = new UserControl1VM();
}
}
}
And the Viewmodel UserControl1VM.cs:
using System.Windows;
namespace DPandMVVM
{
public class UserControl1VM : DependencyObject
{
public UserControl1VM()
{
TextInControl = "TextfromUserControl1VM";
}
public string TextInControl
{
get { return (string)GetValue(TextInControlProperty); }
set { SetValue(TextInControlProperty, value); }
}
public static readonly DependencyProperty TextInControlProperty =
DependencyProperty.Register("TextInControl", typeof(string), typeof(UserControl1VM));
}
}
With this constellation the DP cannot be found in MainWindow.xaml.
What am I doing wrong?
First of all you want DependencyProperty TextInControl
to be declared inside UserControl1
if you want to bind it from outside.
Move the declaration of DP inside of UserControl1
.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string TextInControl
{
get { return (string)GetValue(TextInControlProperty); }
set { SetValue(TextInControlProperty, value); }
}
public static readonly DependencyProperty TextInControlProperty =
DependencyProperty.Register("TextInControl", typeof(string),
typeof(UserControl1));
}
Second you have externally set DataContext of UserControl to UserControl1VM
,
public UserControl1()
{
InitializeComponent();
DataContext = new UserControl1VM(); <-- HERE (Remove this)
}
So WPF binding engine looking for property Text
in UserControl1VM
instead of MainWindowVM
. Remove setting DataContext and update XAML of UserControl1 to this:
<UserControl x:Class="DPandMVVM.UserControl1"
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"
x:Name="userControl1">
<Grid>
<TextBlock Text="{Binding TextInTextBlock, ElementName=userControl1}" />
</Grid>
</UserControl>
Bind DP using ElementName
by setting x:Name
on UserControl.
UPDATE
In case you want to have ViewModel
intact for UserControl
, you have to update binding in MainWindow. Explicitly tell WPF binding engine to look for property in MainWindow's DataContext using ElementName
in binding like this:
<local:UserControl1 TextInControl="{Binding DataContext.Text,
ElementName=mainWindow}" />
For this you need to set x:Name="mainWindow"
on window root level.