Binding from ItemsControl DataTemplate to parent UserControls DependencyProperty - wpf

I want to create an user control which contains ItemsControl with buttons and I want to bind theirs contents to user controls dependency property (something like DisplayMemberPath property).
My xaml.cs code:
public partial class ButtonsItemsSourceControl : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object), typeof(ButtonsItemsSourceControl), null);
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string), typeof(ButtonsItemsSourceControl), null);
public object ItemsSource
{
get { return (ICollection<object>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public string DisplayMember
{
get { return (string)GetValue(DisplayMemberProperty); }
set { SetValue(DisplayMemberProperty, value); }
}
public ButtonsItemsSourceControl()
{
InitializeComponent();
}
}
My xaml code:
<UserControl x:Class="Controls.ButtonsItemsSourceControl"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480" x:Name="root">
<ItemsControl x:Name="ctrl" ItemsSource="{Binding ItemsSource, ElementName=root}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content= ?????/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
What binding expression should I write in Content property to do it ?

Just for clarity, are you asking how to bind a child property to a parent property?
RelativeSource

Related

Combobox usercontrol SelectedItem data binding in WPF container

This is my combobox usercontrol:
<UserControl x:Class="Hexa.Screens.UsrColorPicker"
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:local="clr-namespace:Hexa.Screens"
xmlns:sys="clr-namespace:System;assembly=mscorlib" Height="40" Width="200" Name="uccolorpicker"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ObjectDataProvider MethodName="GetType" ObjectType="{x:Type sys:Type}" x:Key="colorsTypeOdp">
<ObjectDataProvider.MethodParameters>
<sys:String>System.Windows.Media.Colors, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider ObjectInstance="{StaticResource colorsTypeOdp}" MethodName="GetProperties" x:Key="colorPropertiesOdp"/>
</ResourceDictionary>
</UserControl.Resources>
<ComboBox Name="superCombo" ItemsSource="{Binding Source={StaticResource colorPropertiesOdp}}" SelectedValuePath="Name" SelectedValue="{Binding ElementName=uccolorpicker, Path=SelectedColor}" Text="{Binding ElementName=uccolorpicker,Path=Text}" SelectedItem="{Binding ElementName=uccolorpicker, Path=SelectedItem}" SelectedIndex="{Binding ElementName=uccolorpicker, Path=SelectedIndex}" SelectionChanged="superCombo_SelectionChanged" HorizontalContentAlignment="Stretch" >
<ComboBox.ItemTemplate>
<DataTemplate >
<WrapPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Width="20" Height="20" Margin="5" Background="{Binding Name}" />
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontStyle="Italic" FontWeight="Bold" FontFamily="Palatino Linotype" />
</WrapPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This is the code behind:
namespace Hexa.Screens
{
/// <summary>
/// Interaction logic for UsrColorPicker.xaml
/// </summary>
public partial class UsrColorPicker : UserControl
{
public UsrColorPicker()
{
InitializeComponent();
}
public Brush SelectedColor
{
get { return (Brush)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
public int SelectedIndex
{
get { return (int)GetValue(SelectedIndexProperty); }
set { SetValue(SelectedIndexProperty, value); }
}
public int SelectedItem
{
get { return (int)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public string Text
{
get { return (string)GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register("SelectedColor", typeof(Brush), typeof(UsrColorPicker), new UIPropertyMetadata(null));
public static readonly DependencyProperty SelectedIndexProperty =
DependencyProperty.Register("SelectedIndex", typeof(int), typeof(UsrColorPicker), new UIPropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(int), typeof(UsrColorPicker), new UIPropertyMetadata(null));
public static readonly DependencyProperty SelectedTextProperty =
DependencyProperty.Register("Text", typeof(int), typeof(UsrColorPicker), new UIPropertyMetadata(null));
public static readonly RoutedEvent SettingConfirmedEvent =
EventManager.RegisterRoutedEvent("SettingConfirmedEvent", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(UsrColorPicker));
public event RoutedEventHandler SettingConfirmed
{
add { AddHandler(SettingConfirmedEvent, value); }
remove { RemoveHandler(SettingConfirmedEvent, value); }
}
private void superCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(UsrColorPicker.SettingConfirmedEvent));
}
}
}
I am trying to set its SelectedItem,SelectedIndex thru xaml binding in my container's XAML as under:-
<local:UsrColorPicker x:Name="cmbItem_Group_back_color" HorizontalAlignment="Center" Width="205" Height="22" SettingConfirmed="cmbItem_Group_back_color_SettingConfirmed" SelectedColor ="{Binding Path=CurrentRec.Primary_Tone,Mode=TwoWay}" Canvas.Left="97" Canvas.Top="92" />
The code behind is as under:-
form_load()
{
this.DataContext = DataContract_ButtonSettings;
}
But the selecteditem's text is not showing on the combobox as it should.
I found the solution.It was a careless mistake..
The bug was nowhere in the code posted..Actually,i was using the usercontrol's selectedcolor property to bind to the backcolor property of an element in the view.The viewmodel updates the SelectedColor property of the ColorCombobox.The viewmodel was being updated from many places in the code behind.And at one place,the viewmodel's SelectedColor property was being set with the HEX equivalent of the known Color of System.Windows.Media.Colors Known color,and when the view model wud try to bind to that Hex element to the ComboBox,it did not find any matching entry for that Hex value in the dropdown list,and hence,though the background color of the control was being effected,the combobox text showed blank.:-).
anyways,solved it...thanks for your time Ed. :-).

Binding Dependency Property to View Model

I have two user controls defined as follows:
User Control 1
XAML
<UserControl x:Class="TestBindings.UserControlOne"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBindings">
<UserControl.DataContext>
<local:UserControlOneViewModel/>
</UserControl.DataContext>
<StackPanel>
<TextBlock Text="{Binding MyProperty}"/>
<local:UserControlTwo PropertyTwo="{Binding DataContext.MyProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
</StackPanel>
</UserControl>
Code Behind
public partial class UserControlOne : UserControl
{
public UserControlOne()
{
InitializeComponent();
}
}
User Control 2
XAML
<UserControl x:Class="TestBindings.UserControlTwo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBindings">
<UserControl.DataContext>
<local:UserControlTwoViewModel/>
</UserControl.DataContext>
<TextBlock Name="TextBlock" Text="{Binding PropertyTwo}"/>
</UserControl>
Code Behind
public partial class UserControlTwo : UserControl
{
public static readonly DependencyProperty PropertyTwoProperty =
DependencyProperty.Register("PropertyTwo", typeof (string), typeof (UserControlTwo),
new FrameworkPropertyMetadata("Default", OnPropertyTwoChanged));
public UserControlTwo()
{
InitializeComponent();
var propertyTwoBinding = new Binding("PropertyTwo") {Mode = BindingMode.TwoWay};
SetBinding(PropertyTwoProperty, propertyTwoBinding);
}
public string PropertyTwo
{
get { return (string) GetValue(PropertyTwoProperty); }
set { SetValue(PropertyTwoProperty, value); }
}
private static void OnPropertyTwoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var userControlTwo = (UserControlTwo) d;
userControlTwo.PropertyTwo = (string) e.NewValue;
}
}
In UserControlTwo's constructor I bind the dependency property PropertyTwoProperty to a property in the associated ViewModel. I ultimately want to bind this to a property in the ViewModel of UserControlOne, hence UserControlOne xaml
<local:UserControlTwo PropertyTwo="{Binding DataContext.MyProperty, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
However this never seems to get set. Any ideas where I may be going wrong?
I think you are trying to pass a property from the datacontext of UserControlOne to a DependencyProperty in UserControlTwo.
In that case you use the below approach and also remove the setbinding in the code in your UserControl2 Constructor. Let me know if this is what you are looking for.
<UserControl x:Class="TestBindings.UserControlOne"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="userControl"
xmlns:local="clr-namespace:TestBindings">
<UserControl.DataContext>
<local:UserControlOneViewModel/>
</UserControl.DataContext>
<StackPanel>
<TextBlock Text="{Binding MyProperty}"/>
<local:UserControlTwo PropertyTwo="{Binding DataContext.MyProperty, ElementName=userControl,Mode=TwoWay}"/>
</StackPanel>
</UserControl>

WPF XAML - Property update in nested controls

I have a control that exposes a string property named HeaderText in this way:
public partial class HeaderControl : UserControl
{
public static DependencyProperty HeaderTextProperty;
[Category("Header Properties")]
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
static HeaderControl()
{
HeaderTextProperty = DependencyProperty.Register("HeaderText", typeof(string), typeof(HeaderControl), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
}
public HeaderControl()
{
this.DataContext = this;
InitializeComponent();
}
}
HeaderControl's Xaml:
<UserControl x:Class="Col.HMI.Controls.HeaderControl"
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">
<Border Background="{Binding Path=HeaderBackground}" >
<TextBlock Text="{Binding Path=HeaderText}" Foreground="White" TextAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Stretch" FontFamily="Segoe UI Light" FontSize="36" Margin="5"/>
</Border>
and I want to use this HeaderControl in another UserControl, in this way:
OtherControl's Xaml:
<controls:HeaderControl Grid.Row="0" HeaderText="DEMO" />
And this works without problems. But if I bind the HeaderText property to a string property in the OtherControl ViewModel, in this way:
<controls:HeaderControl Grid.Row="0" HeaderText="{Binding Path=SummaryTitle}" />
the bind doesn't work.
This is the SummaryTitle property in the OtherControl ViewModel:
public string SummaryTitle
{
get
{
return _summaryTitle;
}
set
{
_summaryTitle = value; OnPropertyChanged("SummaryTitle");
}
}
PS: I have other controls binded to the OtherControl View Model and they work well.
You are setting DataContext of HeaderControl to itself in the constructor by doing this:
this.DataContext = this;
That means, when you apply some binding to any of the properties in HeaderControl, the Binding engine tries to find the bound property (in your case SummaryTitle) in this control, which it wont find and will fail.
So, to fix your problem, do not set the DataContext of HeaderControl to itself in the Constructor and the Binding engine will try find the properties in the correct DataContext.
Update your HeaderControl constructor to the following, and the bindings should start to work:
public HeaderControl()
{
InitializeComponent();
}
UPDATE
What you are trying to do here is, You want to have DependencyProperty named HeaderText in your UserControl, so that it's value can be set via DataBinding, and then update a value of TextBlock in your UserControl with the value of that DependencyProperty.
You can achieve this by two ways:
1) By updating TextBlock Binding to use ElementNme and Path syntax, XAML would look like this:
<UserControl x:Class="WpfApplication1.HeaderControl"
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="_This">
<Grid>
<TextBlock Text="{Binding ElementName=_This, Path=HeaderText}" FontSize="24" />
</Grid>
</UserControl>
With this approach, whenever the property HeaderText is changed either via Binding or explicitly setting the value.
2) By listening to property value changed event for HeaderText property and then updating the TextBlock accordingly.
For this approach your HeaderControl.xaml would look like:
<UserControl x:Class="WpfApplication1.HeaderControl"
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 x:Name="TextBlockInUserControl"/>
</Grid>
</UserControl>
and the HeaderControl.xaml.cs
public partial class HeaderControl : UserControl
{
public static readonly DependencyProperty HeaderTextProperty;
[Category("Header Properties")]
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
static HeaderControl()
{
HeaderTextProperty = DependencyProperty.Register("HeaderText", typeof (string), typeof (HeaderControl),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnHeaderTextPropertyChanged));
}
private static void OnHeaderTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var headerControl = (HeaderControl) dependencyObject;
headerControl.UpdateTextBlock((string) dependencyPropertyChangedEventArgs.NewValue);
}
void UpdateTextBlock(string text)
{
TextBlockInUserControl.Text = text;
}
public HeaderControl()
{
InitializeComponent();
}
}

Silverlight UserControl Custom Property Binding

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>

How can I access DependencyProperty values from my code-behind constructor?

I have a UserControl called SmartForm which has a DependencyProperty called Status.
In my Window1.xaml, I have the element <local:SmartForm Status="Ready"/>.
I would think then in the constructor of the SmartForm object, that Status would equal "Ready" but instead it equals null.
Why is then the value of the Status property NULL in the constructor of SmartForm?
If not in the UserControl constructor, when do I have access to the value, then?
Window1.xaml:
<Window x:Class="TestPropertyDefine23282.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestPropertyDefine23282"
Title="Window1" Height="300" Width="300">
<Grid>
<local:SmartForm Status="Ready"/>
</Grid>
</Window>
SmartForm.xaml:
<UserControl x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="TestingMessage"/>
</Grid>
</UserControl>
SmartForm.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace TestPropertyDefine23282
{
public partial class SmartForm : UserControl
{
public SmartForm()
{
InitializeComponent();
TestingMessage.Text = Status; //WHY IS STATUS NOT YET SET HERE?
}
#region DependencyProperty: Status
public string Status
{
get
{
return (string)GetValue(StatusProperty);
}
set
{
SetValue(StatusProperty, value);
}
}
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(SmartForm),
new FrameworkPropertyMetadata());
#endregion
}
}
<local:SmartForm Status="Ready"/>
Translates to:
SmartForm f = new SmartForm();
f.Status = Status.Ready;
You will have access to that value when the setter is called.
You can set that testing message as:
...
public static readonly DependencyProperty StatusProperty =
DependencyProperty.Register("Status", typeof(string), typeof(SmartForm),
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnStatusChanged)));
public static void OnStatusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
((SmartForm)d).TestingMessage.Text = e.NewValue.ToString();
}
...
Or as:
<UserControl
x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestPropertyDefine23282"
Height="300" Width="300"
>
<Grid>
<TextBlock
x:Name="TestingMessage"
Text="{Binding Path=Status, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:SmartForm}}}"
/>
</Grid>
</UserControl>
Szymon Rozga exlained the problem in a great way. You check the parameter before it is set but after the constructor is initialized.
A good solution is using the loaded event instead like so:
(Untested)
public SmartForm()
{
InitializeComponent();
Loaded += (sender, args) =>
{
TestingMessage.Text = Status;
};
}
This is kind of tertiary, but why do you need this setter at all?
<UserControl x:Class="TestPropertyDefine23282.SmartForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Control"
Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding Path=Status, ElementName=Control}" />
</Grid>
</UserControl>

Resources