WPF: DependencyProperty refusing to work - wpf

I'm trying to register 3 dependency properties on a Window to control it's formatting. I've looked over and over the code but I must be missing something.
public static readonly DependencyProperty TextColorProperty = DependencyProperty.Register("TextColor", typeof(Color), typeof(WinStickyFingers), new PropertyMetadata(Colors.White));
public Color TextColor {
get { return (Color)base.GetValue(TextColorProperty); }
set { base.SetValue(TextColorProperty, value); }
}
public static readonly DependencyProperty BackgroundColorProperty = DependencyProperty.Register("BackgroundColor", typeof(Color), typeof(WinStickyFingers), new PropertyMetadata(Colors.Black));
public Color BackgroundColor {
get { return (Color)base.GetValue(BackgroundColorProperty); }
set {
base.SetValue(BackgroundColorProperty, value);
}
}
<TextBlock DockPanel.Dock="Top" Text="{Binding Name}" Foreground="{Binding TextColor,Converter={StaticResource DebugConverter}}" Background="{Binding Path=BackgroundColor}" />
I'm using Bea Stollnitz's debugging method but my breakpoint isn't even triggered.

What is the DataContext of the TextBlock? How does it know that it is supposed to bind to the properties on your Window?
You need to either set DataContext to the Window instance, or set the Source (or RelativeSource, or ElementName) properties on your bindings. All of these properties exist as a means of resolving the bound object for your Binding. DataContext is a fallback if none of the others is set, but I'm guessing that you haven't set that either.

Related

Binding a Color to a DependencyProperty in UserControl

I have a UserControl that has a Grid with a Background property that is bound. All of my other bindings work as expected, but for some reason, the only color I get in my UserControl is the default value I set for the DependencyProperty.
Referencing the UserControl in MainWindow.xaml:
<controls:MyUserControl Title="{Binding Path=MyObjects[0].Title" MyControlColor="{Binding Path=MyObjects[0].Color}" />
Title shows up as expected but the color is unchanged.
MyUserControl code (I use MyControlColorBrush for the color source, which just converts MyControlColor to a SolidColorBrush. Code on down.):
<Grid Background="{Binding Path=MyControlColorBrush, RelativeSource={RelativeSource AncestorType=UserControl}}">
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Grid>
MyUserControl.xaml.cs code:
public Color MyControlColor
{
get { return (Color)GetValue(MyControlColorProperty); }
set { SetValue(MyControlColorProperty, value); }
}
public static readonly DependencyProperty MyControlColorProperty = DependencyProperty.Register("MyControlColor", typeof(Color), typeof(MyUserControl), new PropertyMetadata(Colors.Black));
And then a property that just converts the color to a SolidColorBrush:
public SolidColorBrush MyControlColorBrush
{
get { return new SolidColorBrush(MyControlColor); }
}
Any ideas on what I could be missing? If I check the value of MyControlColor, it's showing the right color, but the background of the Grid just isn't changing from Black.
The binding to MyControlColorBrush only happens once when your page is first loaded. Your binding to MyObjects[0].Color is causing your dependency property to update but there's nothing indicating to the rest of your app that MyControlColorBrush needs to be updated as well.
There are a few ways to achieve this, the easiest is probably to just create a read-only dependency property for your brush that you update whenever you detect a change in your color property (this is similar to how the Width/ActualWidth properties work). Your control will need a DP for the color:
public Color MyControlColor
{
get { return (Color)GetValue(MyControlColorProperty); }
set { SetValue(MyControlColorProperty, value); }
}
public static readonly DependencyProperty MyControlColorProperty =
DependencyProperty.Register("MyControlColor", typeof(Color), typeof(MyUserControl),
new PropertyMetadata(Colors.Black, OnColorChanged));
And then a read-only DP for the brush:
public Brush MyControlColorBrush
{
get { return (Brush)GetValue(MyControlColorBrushProperty); }
protected set { SetValue(MyControlColorBrushPropertyKey, value); }
}
private static readonly DependencyPropertyKey MyControlColorBrushPropertyKey
= DependencyProperty.RegisterReadOnly("MyControlColorBrush", typeof(Brush), typeof(MyUserControl),
new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.None));
public static readonly DependencyProperty MyControlColorBrushProperty = MyControlColorBrushPropertyKey.DependencyProperty;
And you'll update the brush whenever your color DP changes:
private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MyUserControl).MyControlColorBrush = new SolidColorBrush((Color)e.NewValue);
}
GUI elements in your custom control then bind to the read-only DP, e.g.:
<Grid Background="{Binding Path=MyControlColorBrush, RelativeSource={RelativeSource AncestorType=local:MyUserControl}}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

Pass textbox from a page to Custom usercontrol using dependencyProperty

I have a Custom user control in a silver light Project.
I use it in other page and want to Pass textbox to Custom User control.
For this I create dependcy as below :
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("TextBoxControl", typeof(TextBox), typeof(SpellCheck), new PropertyMetadata(false));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(MyPropertyProperty); }
set
{
SetValue(MyPropertyProperty, value);
TextSpell = value;
}
}
Here TextSpell is a textbox.
And I use this property in a silver light page as below:
<TextBox x:Name="txtNote" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="400"/>
<myButton:SpellCheck x:Name="btnSpell" Grid.Row="3" TextBoxControl="txtNote" Grid.Column="1" Width="20" Height="20" Margin="403,0,0,0" HorizontalAlignment="Left"/>
But I give s me a error : "The Typeconvertor for Texbox dose not support converting from a string"
So How can I pass a text box in custom usercontrol.
Thanks,
Hitesh
You can not simply use the field name (x:Name) string of the TextBox as a value for your TextBoxControl property. Instead you may use an ElementName binding like this:
<myButton:SpellCheck TextBoxControl="{Binding ElementName=txtNote}" ... />
And there are more things wrong:
In the CLR wrappers of a dependency property, you should never call anything else than GetValue and SetValue. The explanation is given in the XAML Loading and Dependency Properties article on MSDN. Instead, you have to have a PropertyChangedCallback registered with the property metadata.
There is a naming convention for the static dependency property fields. They should be named like the property, with a trailing Property.
The default value has to match the property type. Your false value is not valid, and might be null instead. But as that is the default anyway, you should leave it out completely.
The declaration would now look like this:
public static readonly DependencyProperty TextBoxControlProperty =
DependencyProperty.Register(
"TextBoxControl", typeof(TextBox), typeof(SpellCheck),
new PropertyMetadata(TextBoxControlPropertyChanged));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(TextBoxControlProperty); }
set { SetValue(TextBoxControlProperty, value); }
}
private static void TextBoxControlPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var spellCheck = (SpellCheck)obj;
spellCheck.TextSpell = (TextBox)e.NewValue;
}

Property bound to DependencyProperty won't update despite TwoWay Binding set

I have a little problem here. I've created custom TreeView using RadTreeView. It all works nice, but I've encountered an obstacle. I've set DependencyProperty for SelectedItem in TreeView. I nest my control in View, bind property to SelectedItem in TwoWay mode, but bound property won't update, it's null all the time, despite DependencyProperty value being set.
Here's tree xaml:
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:sdk='http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'
xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' x:Name='this' >
<Grid.Resources>
<DataTemplate x:Key='ChildTemplate'>
<TextBlock Text='{Binding Path=ChildPath}' Margin='5,0' />
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key='NameTemplate' ItemsSource='{Binding ChildrenCollectionPath}' ItemTemplate='{StaticResource ChildTemplate}'>
<TextBlock Text='{Binding Path=ParentPath }' Padding='7'/>
</telerik:HierarchicalDataTemplate>
</Grid.Resources>
<telerik:RadTreeView x:Name='rtvTreeView' Padding='5' BorderThickness='0' IsEditable='False' IsLineEnabled='True' IsExpandOnDblClickEnabled='False' ItemTemplate='{StaticResource NameTemplate}' />
</Grid>
Below is way I nest the control in View:
<windows:TreeViewReuse CollectionSource="{Binding SitesCollectionWithAddress}" ParentPath="Napis" Grid.Column="0" BorderThickness="2" SelectedItemD="{Binding SelectedSide, ElementName=this, UpdateSourceTrigger=Explicit, Mode=TwoWay}" ChildPath="FullAddress" ChildrenCollectionPath="AdresyStrony" BorderBrush="Red" DoubleClickCommand="{Binding TreeViewDoubleClick}">
</windows:TreeViewReuse>
And here's Tree's code behind in parts:
public partial class TreeViewReuse : UserControl
{
static Telerik.Windows.FrameworkPropertyMetadata propertyMetaData = new Telerik.Windows.FrameworkPropertyMetadata(null,
Telerik.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(SelectedItemChangedCallback));
public object SelectedItemD
{
get { return GetValue(SelectedItemDProperty); }
set { SetValue(SelectedItemDProperty, value); }
}
public static readonly DependencyProperty SelectedItemDProperty =
DependencyProperty.Register("SelectedItemD", typeof(object), typeof(TreeViewReuse), propertyMetaData);
public TreeViewReuse()
{
InitializeComponent();
Loaded += new RoutedEventHandler(TreeViewReuse_Loaded);
}
void treeView_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
SelectedItemD = _treeView.SelectedItem;
}
static private void SelectedItemChangedCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
}
Does anyone have an idea why property bound to SelectedItemD does not update? I don't care about setting tree's selected item from it, I only want to set it to selected item.
Here's property:
public StronaSprawy SelectedSide
{
get
{
return _selectedSide;
}
set
{
_selectedSide = value;
}
}
Your Dependency Property looks fine.. all except for that Telerik.Windows.FrameworkPropertyMetadata instance.
Silverlight does not support setting meta data options, so I cant think how the Telerik implementation will achieve that. It is possible that Telerik have their own DP implementation, or even that this type of property meta data only works with their controls.
Try using the standard System.Windows.PropertyMetaData type instead and see if that works for you.

How to define a dependency property in a user control that just bubbles up a value from one of its children?

I am creating a ToggleSwitchItem user control, which contains a ToggleSwitch and a TextBlock. I have defined a dependency property called IsChecked which I just want to use to expose the IsChecked property of the private ToggleSwitch child.
But the data binding doesn't work... It just stays at the default value when loaded.
What am I missing?
Code:
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
"IsChecked",
typeof(bool),
typeof(ToggleSwitchItem),
new PropertyMetadata(new PropertyChangedCallback
(OnIsCheckedChanged)));
public bool IsChecked
{
get
{
return (bool)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
private static void OnIsCheckedChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
ToggleSwitchItem item = (ToggleSwitchItem)d;
bool newValue = (bool)e.NewValue;
item.m_switch.IsChecked = newValue;
}
for the data binding, I'm using to following:
<phone:PhoneApplicationPage.Resources>
<myApp:SharedPreferences x:Key="appSettings"/>
</phone:PhoneApplicationPage.Resources>
IsChecked="{Binding Source={StaticResource appSettings},
Path=SomeProperty, Mode=TwoWay}"
The SharedPreferences class is working fine, as it works without issue when bound to a plain vanilla ToggleSwitch's IsChecked property exactly as per above.
Thanks!
SOLUTION (with help from Anthony):
I bind my child toggle switch to my user control in the user control's constructor like so:
Binding binding = new Binding();
binding.Source = this;
binding.Path = new PropertyPath("IsChecked");
binding.Mode = BindingMode.TwoWay;
m_switch.SetBinding(ToggleSwitch.IsCheckedProperty, binding);
And I remove the callback as I no longer need it:
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
"IsChecked",
typeof(bool),
typeof(ToggleSwitchItem),
null);
public bool IsChecked
{
get
{
return (bool)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
I can't quite see what is actually wrong with the code you've show so far, except that you haven't show how the user toggling the switch would actually cause the IsChecked property to change.
Have you try using binding inside the UserControl:
<ToggleButton IsChecked="{Binding Parent.IsChecked, ElementName=LayoutRoot, Mode=TwoWay}" />
You do not need the OnPropertyChanged callback with this approach.
Check the DataContext of your control.Which means 2 things : All instances of your control must have right DataContext to work -ok-, and also you should not 'break' this DataContext when you define the control (at the Class level). If, when you define your control, you set the DataContext to 'this' / Me in code or to 'Self' in xaml, it nows refer only to itself and forget about the DataContext in which it is when you instanciate it in your application -- Binding fails.
If you have to refer to your control's properties within your control Xaml, use a binding with findAncestor / AncestorType = ToggleSwitchItem Or name your control in Xaml and bind with its ElementName.
Maybe this could help
public bool IsChecked
{
get { return GetValue(IsCheckedProperty) is bool ? (bool) GetValue(IsCheckedProperty) : false; }
set
{
SetValue(IsCheckedProperty, value);
}
}

How to bind to a WPF dependency property when the datacontext of the page is used for other bindings?

How to bind to a WPF dependency property when the datacontext of the page is used for other bindings? (Simple question)
The datacontext of the element needed to be set.
XAML:
<Window x:Class="WpfDependencyPropertyTest.Window1" x:Name="mywindow">
<StackPanel>
<Label Content="{Binding Path=Test, ElementName=mywindow}" />
</StackPanel>
</Window>
C#:
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test",
typeof(string),
typeof(Window1),
new FrameworkPropertyMetadata("Test"));
public string Test
{
get { return (string)this.GetValue(Window1.TestProperty); }
set { this.SetValue(Window1.TestProperty, value); }
}
Also see this related question:
WPF DependencyProperties
In XAML:
Something="{Binding SomethingElse, ElementName=SomeElement}"
In code:
BindingOperations.SetBinding(obj, SomeClass.SomethingProperty, new Binding {
Path = new PropertyPath(SomeElementType.SomethingElseProperty), /* the UI property */
Source = SomeElement /* the UI object */
});
Though usually you will do this the other way round and bind the UI property to the custom dependency property.

Resources