I have a trivial user control:
<UserControl x:Class="Xxx.SimpleUserControl.SimpleTextUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root">
<StackPanel Background="Blue">
<TextBlock x:Name="TitleTextBlock" Text="{Binding ElementName=root, Path=Title}" Background="White" Width="200" Height="30" Margin="5" />
<TextBlock Text="{Binding ElementName=root, Path=Time}" Background="White" Width="200" Height="30" Margin="9" />
</StackPanel>
</UserControl>
and the code behind:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Xxx.SimpleUserControl
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class SimpleTextUserControl : UserControl
{
public SimpleTextUserControl()
{
InitializeComponent();
}
[Browsable(true)]
[Category("SimpleControl")]
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(SimpleTextUserControl), new FrameworkPropertyMetadata("hello"));
[Browsable(true)]
[Category("SimpleControl")]
public DateTime Time
{
get { return (DateTime)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
// Using a DependencyProperty as the backing store for Time. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TimeProperty =
DependencyProperty.Register("Time", typeof(DateTime), typeof(SimpleTextUserControl), new UIPropertyMetadata(DateTime.Now));
}
}
I naively expect the VS2010 designer for the UserControl to display my default metadata values for my two controls - "hello" in one textblock, and today's date and time in other, but they are empty.
If I compile, and drop the control in to a WPF application, it renders fine, but not whilst in the UserControl project xaml view/designer.
I've tried changing the datacontext around, binding in different ways, implementing OnPropertyChanged etc., but nothing makes the data render in the UserControl project's design view.
Does anyone know the answer to this one? I've searched around, and either it's so obvious I'm missing it, or it's 'just the way it is'.
I think you'll need to use a "DesignTime" DataContext. Add the following to your UserControl Xaml file
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:YourNamespace"
mc:Ignorable="d"
And then set the DesignTime DataContext with
d:DataContext="{d:DesignInstance local:SimpleTextUserControl,
IsDesignTimeCreatable=True}"
And remove ElementName from the Bindings
<UserControl x:Class="YourNamespace.SimpleTextUserControl"
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"
xmlns:local="clr-namespace:YourNamespace"
mc:Ignorable="d"
x:Name="root"
d:DataContext="{d:DesignInstance local:SimpleTextUserControl,
IsDesignTimeCreatable=True}">
<StackPanel Background="Blue">
<TextBlock x:Name="TitleTextBlock" Text="{Binding Path=Title}" Background="White" Width="200" Height="30" Margin="5" />
<TextBlock Text="{Binding Path=Time}" Background="White" Width="200" Height="30" Margin="9" />
</StackPanel>
</UserControl>
If you're still having problems getting this to work I uploaded a small sample project which you can compare to: http://www.mediafire.com/?gan28oeel4qf7ik
Related
I'd like to set a property of a re-defined UserControl (for example its background color) to a property of the class. For example.
If I define the background of a Button to a property (<Button x:Name="myButton" Background="{Binding ColorName}"/>), it works fine. However, if I do the same for a re-defined UserControl (<local:MyUserControl Background="{Binding Path=ColorName}"/>), it does not.
What's funny though, is that, if I do <local:MyUserControl Background="{Binding Background, ElementName=myButton}"/>, it works perfectly fine.
Could I have some help on that? I must be missing something.
Thanks!
EDIT
Here is all the code. The setting of the background color worked fine. What solved this was to set properly the MainWindow.DataContext and to remove the DataContext = this in MyUserControl.xaml.cs. Setting Color as a DependencyProperty is also useful to be able to change the Color setting in a later execution of the code.
Nonetheless, while removing DataContext=this in MyUserControl.xaml.cs,
the {Binding TextContent} does not work and needs to be replaced by {Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}.
MainWindow.xaml
<Window x:Class="BindingBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:BindingBug"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="0"
x:Name="myButton"/>
<c:MyUserControl Background="{Binding Background, ElementName=myButton}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="1"/>
<c:MyUserControl Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="2"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace BindingBug
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Color = Brushes.Red;
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));
public Brush Color
{
get
{
return (Brush)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
}
}
MyUserControl.xaml
<UserControl x:Class="BindingBug.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"
xmlns:c="clr-namespace:BindingBug"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="13"
Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}"
VerticalAlignment="Center"/>
</Grid>
</UserControl>
MyUserControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingBug
{
/// <summary>
/// Interaction logic for NumberDataHolder.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));
public string TextContent
{
get
{
return (string)GetValue(TextContentProperty);
}
set
{
SetValue(TextContentProperty, value);
}
}
}
}
EDIT 2
I tried to acheive the same results without having to declare the whole Text="{Binding TextContent, RelativeSource={RelativeSource AncestorType=c:MyUserControl}}" inside TextBlock. So, following #KeithStein advice, I placed DataContext="{Binding RelativeSource={RelativeSource Self}}" inside MyUserControl and only kept Text="{Binding TextContent}"inside TextBlock. That, however cancels the effect of setting Background="{Binding Path=Color}" in MainWindow.xaml. Any idea why? Is there another possibility to set Background="{Binding Path=Color}" in MainWindow.xaml and to only keepText="{Binding TextContent}"inside TextBlock?
MainWindow.xaml
<Window x:Class="BindingBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:BindingBug"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="0"
x:Name="myButton"/>
<c:MyUserControl Background="{Binding Background, ElementName=myButton}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="1"/>
<c:MyUserControl Background="{Binding Path=Color}"
Width="250"
Height="30"
Content="I am bound to be RED!"
Grid.Row="2"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace BindingBug
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Color = Brushes.Red;
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(MainWindow));
public Brush Color
{
get
{
return (Brush)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
}
}
MyUserControl.xaml
<UserControl x:Class="BindingBug.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"
xmlns:c="clr-namespace:BindingBug"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="13"
Text="{Binding TextContent}"
VerticalAlignment="Center"/>
</Grid>
</UserControl>
MyUserControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingBug
{
/// <summary>
/// Interaction logic for NumberDataHolder.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TextContentProperty = DependencyProperty.Register("TextContent", typeof(string), typeof(MyUserControl));
public string TextContent
{
get
{
return (string)GetValue(TextContentProperty);
}
set
{
SetValue(TextContentProperty, value);
}
}
}
}
This answer developed gradually through back and forth comments with OP. To summarize:
Use a Brush-type dependency property for your color. Brush because that is the type of the Background property that you want to bind to, and a dependency property so that updates of the property trigger any bindings to refresh.
When binding inside a Window or UserControl, you need to set DataContext, which is essentially the default sourced used by bindings.
For a Window, add DataContext="{Binding RelativeSource={RelativeSource Self}}" to the opening tag. This sets the default source for all controls contained within to the Window itself.
For a UserControl, add the following to the outer-most panel of said control: DataContext={Binding RelativeSource={RelativeSource AncestorType=UserControl}} (UserControl can be replaced with the name of your particular control, i.e. c:MyUserControl). This tells everything inside that root panel to use the UserControl as the default source. You can't use RelativeSource Self in this case, because then instances of the MyUserControl will bind to themselves when placed inside Windows, instead of inheriting the Window's DataContext.
I want to create an UserControl with a TextBlock as header and another TextBlock as content
HeaderTextBlock.xaml
<UserControl x:Class="GetPageDataFacebookAPI.HeaderTextBlock"
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"
xmlns:local="clr-namespace:GetPageDataFacebookAPI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Header" Opacity=".6" Margin="5" />
<TextBlock Text="Text" Margin="5" />
</StackPanel>
</UserControl>
But how can I use it and binding value to Header and Content TextBlock?
<local:HeaderTextBlock Header="..." and Text="..." />
You just create dependency properties to expose those elements in code behind. Then when you use the control in another view you can do just that.
Add a name to the two TextBlock's and then add dependency properties to change them in the code behind.
<StackPanel Orientation="Horizontal">
<TextBlock Text="Header"
Opacity=".6"
Margin="5"
Name="TextBlockHeader"/>
<TextBlock Text="Text"
Margin="5"
Name="TextBlockText"/>
</StackPanel>
Code Behind for control...
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register(nameof(Header), typeof(string), typeof(HeaderTextBlock), new PropertyMetadata("", (s, e) => (s as HeaderTextBlock).TextBlockHeader.Text = (string)e.NewValue));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(HeaderTextBlock), new PropertyMetadata("", (s, e) => (s as HeaderTextBlock).TextBlockText.Text = (string)e.NewValue));
Then you can use it in another view or control like so... Works with binding also.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:HeaderTextBlock Header="{Binding Header}" Text="Hello WOrld"/>
</Grid>
Create two plain CLR properties, or
Create two DependencyProperty corresponding to Header and Text if you need Binding.
Tutorial
You need to creat custom control, and not use userControl:
https://msdn.microsoft.com/en-gb/library/cc295235.aspx
I have three controls in my application of type MyUserControl. MyUserControl contains a Label which I want to bind to a string located in the Application Settings. Each of the three instances of MyUserControl has its own string in the Application Settings named Description1, Description2 and Description3 respectively.
The problem is that I cannot set the path of the binding in the UserControl to the name of the string located in the Application Settings because then every instance of MyUserControl would bind to the same string.
I have managed to get something working but as I have learned while working with WPF is that the solution I come up with is never the best way to do things :), so I was wondering if there is a better way to do this? Below is the relevant code I am using now:
MyUserControl.xaml.cs
public partial class MyUserControl : UserControl
{
public static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(MyUserControl));
public string Description { get { return (string)GetValue(DescriptionProperty); } set { SetValue(DescriptionProperty, value); } }
}
MyUserControl.xaml
<UserControl x:Class="MyApplication.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"
xmlns:local="clr-namespace:MyApplication"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Name="myUserControl">
...
<Label Content="{Binding ElementName=myUserControl, Path=Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,6" />
MainWindow.xaml
xmlns:properties="clr-namespace:MyApplication.Properties"
...
<local:MyUserControl Description="{Binding Source={x:Static properties:Settings.Default}, Path=Description1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="myUserControl1" DataContext="{Binding ElementName=MainWindow, Path=Params}" />
<local:MyUserControl Description="{Binding Source={x:Static properties:Settings.Default}, Path=Description2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="myUserControl2" DataContext="{Binding ElementName=MainWindow, Path=Params}" />
What is the proper way to implement Custom Properties in Silverlight UserControls?
Every "Page" in Silverlight is technically a UserControl (they are derived from the UserControl class). When I say UserControl here, I mean a Custom UserControl that will be used inside many different pages in many different scenarios (similar to an ASP.NET UserControl).
I would like the Custom UserControl to support Binding and not rely on the Name of the Property it is binding to, to always be the same. Instead, I would like the UserControl itself to have a property that the Controls inside the UserControl bind to, and the ViewModels outside the UserControl also bind to. (please see the example below)
Binding within the UserControl works, Binding within the MainPage works, The Binding I set up between the MainPage and the UserControl does not work. Specifically this line:
<myUserControls:MyCustomUserControl x:Name="MyCustomControl2"
SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}"
Width="200" Height="50" />
example output:
MainPage.xaml
<UserControl x:Class="SilverlightCustomUserControl.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:myUserControls="clr-namespace:SilverlightCustomUserControl"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Canvas x:Name="LayoutRoot">
<StackPanel Orientation="Vertical">
<TextBlock Text="UserControl Binding:" Width="200"></TextBlock>
<myUserControls:MyCustomUserControl x:Name="MyCustomControl2" SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200" Height="50" />
<TextBlock Text="MainPage Binding:" Width="200"></TextBlock>
<TextBox Text="{Binding MainPageSelectedText, Mode=TwoWay}" Width="200"></TextBox>
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding MainPageSelectedText}" Width="200" Height="24"></TextBlock>
</Border>
</StackPanel>
</Canvas>
</UserControl>
MainPage.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MainPage : UserControl, INotifyPropertyChanged
{
//NOTE: would probably be in a ViewModel
public string MainPageSelectedText
{
get { return _MainPageSelectedText; }
set
{
string myValue = value ?? String.Empty;
if (_MainPageSelectedText != myValue)
{
_MainPageSelectedText = value;
OnPropertyChanged("MainPageSelectedText");
}
}
}
private string _MainPageSelectedText;
public MainPage()
{
InitializeComponent();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
PropertyChangedEventHandler ph = this.PropertyChanged;
if (ph != null)
ph(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}
MyCustomUserControl.xaml
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<StackPanel>
<TextBox Text="{Binding SelectedText, Mode=TwoWay}" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding SelectedText}" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
MyCustomUserControl.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MyCustomUserControl : UserControl
{
public string SelectedText
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));
public MyCustomUserControl()
{
InitializeComponent();
}
private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
}
}
References (how I got this far):
use DependencyPropertys:
http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx
use DependencyPropertys, add x:Name to your UserControl - add Binding with ElementName, set Custom property again in the PropertyChangedCallback method:
Setting Custom Properties in UserControl via DataBinding
don't use custom properties, rely on underlying datacontext names (I do not like this solution):
wpf trouble using dependency properties in a UserControl
I understand it as the reason your control is not receiving the new value from the maim page is that you are setting the DataContext of the control. If you hadn't then the control's DataContext will be inherited from its parent, the main page in this case.
To get this to work I removed you control's DataContext setting, added an x:Name to each control and set the binding in the constructor of the control using the [name].SetBinding method.
I did the binding in the ctor as I couldn't figure out a way of setting the Source property of the declarative binding in the xaml to Self. i.e. {Binding SelectedText, Mode=TwoWay, Source=[Self here some how]}. I did try using RelativeSource={RelativeSource Self} with no joy.
NOTE: All this is SL3.
The Issue was the UserControl was throwing a DataBinding error (visible in the Output window while debugging)
Because The UserControl's DataContext was set to "Self" in its own xaml, it was looking for the MainPageSelectedText within its own context (it was not looking for the MainPageSelectedText within the "MainPage" which is where you might think it would look, because when you are physically writing/looking at the code that is what is in "context")
I was able to get this "working" by setting the Binding in the code behind. Setting the binding in the code behind is the only way to set the UserControl itself as the "Source" of the binding. But this only works if the Binding is TwoWay. OneWay binding will break this code. A better solution altogether would be to create a Silverlight Control, not a UserControl.
See Also:
http://social.msdn.microsoft.com/Forums/en-US/silverlightcontrols/thread/052a2b67-20fc-4f6a-84db-07c85ceb3303
http://msdn.microsoft.com/en-us/library/cc278064%28VS.95%29.aspx
MyCustomUserControl.xaml
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid>
<StackPanel>
<TextBox x:Name="UserControlTextBox" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock x:Name="UserControlTextBlock" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
MyCustomUserControl.xaml.cs
namespace SilverlightCustomUserControl
{
public partial class MyCustomUserControl : UserControl
{
public string SelectedText
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));
public MyCustomUserControl()
{
InitializeComponent();
//SEE HERE
UserControlTextBox.SetBinding(TextBox.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText"), Mode = BindingMode.TwoWay });
UserControlTextBlock.SetBinding(TextBlock.TextProperty, new Binding() { Source = this, Path = new PropertyPath("SelectedText") });
//SEE HERE
}
private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//empty
}
}
}
Instead of binding data context to self, you can set the binding in xaml by adding an x:Name for the user control and then binding in the user control xaml follows:
<UserControl
x:Class="SilverlightCustomUserControl.MyCustomUserControl"
x:Name="myUserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid>
<StackPanel>
<TextBox Text="{Binding SelectedText, ElementName=myUserContol, Mode=TwoWay}" />
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding SelectedText,ElementName=myUserControl}" Height="24"></TextBlock>
</Border>
</StackPanel>
</Grid>
</UserControl>
When developing WPF UserControls, what is the best way to expose a DependencyProperty of a child control as a DependencyProperty of the UserControl? The following example shows how I would currently expose the Text property of a TextBox inside a UserControl. Surely there is a better / simpler way to accomplish this?
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="LightCyan">
<TextBox Margin="8" Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</StackPanel>
</UserControl>
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication3
{
public partial class UserControl1 : UserControl
{
public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new PropertyMetadata(null));
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value); }
}
public UserControl1() { InitializeComponent(); }
}
}
That is how we're doing it in our team, without the RelativeSource search, rather by naming the UserControl and referencing properties by the UserControl's name.
<UserControl x:Class="WpfApplication3.UserControl1" x:Name="UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="LightCyan">
<TextBox Margin="8" Text="{Binding Path=Text, ElementName=UserControl1}" />
</StackPanel>
</UserControl>
Sometimes we've found ourselves making too many things UserControl's though, and have often times scaled back our usage. I'd also follow the tradition of naming things like that textbox along the lines of PART_TextDisplay or something, so that in the future you could template it out yet keep the code-behind the same.
You can set DataContext to this in UserControl's constructor, then just bind by only path.
CS:
DataContext = this;
XAML:
<TextBox Margin="8" Text="{Binding Text} />