Reputation: 217
I want to realize a binding between several properties. Is it possible ?
I have a main window class named "MainWindow" which owns a property "InputText". This class contains a user control named MyUserControl. MyUserControl has a text box bound to a dependency property "MyTextProperty"
I would like to bind the property "InputText" of my main window with the dependency property "MyTextProperty" of my user control. So, if the user writes a text, I want that the properties "InputText", "MyTextProperty", "MyText" are updated.
User control code:
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MyUserControl.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public string MyText
{
get { return (string)GetValue(MyTextProperty); }
set { SetValue(MyTextProperty, value); }
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(string), typeof(MyUserControl), new PropertyMetadata(0));
public MyUserControl()
{
this.DataContext = this;
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
}
WPF user control code:
<UserControl x:Class="WpfApplication1.MyUserControl"
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="25 " d:DesignWidth="100"
Background="Black">
<Grid>
<TextBox Height="20" Width="100" Text="{Binding MyText}"></TextBox>
</Grid>
</UserControl>
Main window code:
using System;
using System.Linq;
using System.Windows;
using System.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string inputText;
public string InputText
{
get { return inputText; }
set
{
inputText = value;
NotifyPropertyChanged("InputText");
}
}
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
}
WPF main window 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:myNS="clr-namespace:WpfApplication1"
Title="MainWindow" Height="80" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<myNS:MyUserControl x:Name="test" MyText="{Binding InputText}"></myNS:MyUserControl>
<Button Name="cmdValidation" Content="Validation" Height="20"></Button>
</StackPanel>
</Grid>
</Window>
Thank you !
Upvotes: 0
Views: 2572
Reputation: 4322
If you want your posted code to work with as little changes as possible then:
In MainWindow.xaml, change
MyText="{Binding InputText}"
to
MyText="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.InputText, Mode=TwoWay}"
You need TwoWay if you want the UC to update InputText.
Also, in MyUserControl.xaml.cs, in your DependencyProperty.Register statement, you have the PropertyMetadata default value set to 0 for a string -- change it to something appropriate for a string - like null or string.empty.
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(string), typeof(MyUserControl), new PropertyMetadata(null));
If you want to change the code up a bit, you could make this more complex in the user control but simpler when you use it by:
Making the dependency property, MyText, bind two way by default
Stop setting the DataContext in the user control
Change the UC xaml text binding to use a relative source to the UC
I always find code easier to understand, so here are modified versions of your files: MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myNS="clr-namespace:WpfApplication1"
Title="MainWindow" Height="180" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock>
<Run Text="MainWindow.InputText: " />
<Run Text="{Binding InputText}" />
</TextBlock>
<TextBlock>
<Run Text="MyUserControl.MyText: " />
<Run Text="{Binding ElementName=test, Path=MyText}" />
</TextBlock>
<myNS:MyUserControl x:Name="test" MyText="{Binding InputText}"></myNS:MyUserControl>
<Button Name="cmdValidation" Content="Validation" Height="20"></Button>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string inputText = "Initial Value";
public string InputText
{
get { return inputText; }
set
{
inputText = value;
NotifyPropertyChanged("InputText");
}
}
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
}
MyUserControl.xaml
<UserControl x:Class="WpfApplication1.MyUserControl"
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="25 " d:DesignWidth="100"
Background="Black">
<Grid>
<TextBox Height="20" Width="100" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=MyText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
</UserControl>
MyUserControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MyUserControl.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public string MyText
{
get { return (string)GetValue(MyTextProperty); }
set { SetValue(MyTextProperty, value); }
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(string), typeof(MyUserControl), new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true });
public MyUserControl()
{
InitializeComponent();
}
}
}
Upvotes: 4
Reputation: 9713
Firstly,
this.DataContext = this;
No. Just, no. You are overriding the DataContext
of the UserControl
set by it's parent window.
For your UserControl
, give it an x:Name
, and bind directly to the dependency property.
<UserControl
...
x:Name="usr">
<TextBox Text="{Binding MyText, ElementName=usr}" ... />
After you've done that, you can then simply bind your MyText
property to the DataContext
of the MainWindow
.
<myNS:MyUserControl x:Name="test" MyText="{Binding InputText}" />
Upvotes: 1