WPF Custom binding Collection to non dependency property - wpf

I've created my own custom binding class and added a property to it:
public BindingGroupCollection BindingGroups
{
get { return validationResultGroup; }
set { validationResultGroup = value; }
}
public class BindingGroupCollection : ObservableCollection<BindingGroup> { }
In my xaml class i declared the objects and collection:
<local:BindingGroup x:Key="BG1"/>
<local:BindingGroup x:Key="BG2"/>
<local:BindingGroupCollection x:Key="BindingGroups1">
<StaticResourceExtension ResourceKey="BG1"/>
<StaticResourceExtension ResourceKey="BG2"/>
</local:BindingGroupCollection>
And i want to use this in my binding eg.:
<TextBox Text="{local:CustomBinding BindingGroups={Binding Source={StaticResource BindingGroups1}}}"/>
But i get an error that the target is not a dependeny object. Any help?

You can't do that, because a Binding isn't a DependencyObject, so it can't have have dependency properties.
However, in your case you don't need a binding, you can use the StaticResource directly:
<TextBox Text="{local:CustomBinding BindingGroups={StaticResource BindingGroups1}}"/>

Related

Is it possible to bind to Windows.Storage.ApplicationData.Current.LocalSettings.Values?

I have a control with a value that I would like to be mapped to Windows.Storage.ApplicationData.Current.LocalSettings.Values["MyValue"].
Can I bind to this variable directly or do I need to add a viewmodel?
To do that, you would need the x:Static markup extension, which unfortunately is unavailable on Windows Phone.
So, just assign a viewmodel to your page, and expose the value in a property:
public string MyValue
{
get
{
return Windows.Storage.ApplicationData.Current.LocalSettings.Values["MyValue"];
}
}
Or you can expose the whole dictionary:
public Windows.Storage.ApplicationDataContainer Settings
{
get
{
return Windows.Storage.ApplicationData.Current.LocalSettings;
}
}
Then bind it from the XAML:
<TextBlock Text="{Binding Path=Settings[MyValue]}" />

Hiding a Dependency Property

Just wondering if this is a good practice or if it could cause any troubles in the long run. To be honest, I'm surprised it even works - it does the job, but I'm not sure if it's risky.
Basically we created a NumericTextBox that derives from TextBox, and we overrode the Text property with the new keyword to remove commas from the text:
public class NumericTextBox : TextBox
{
public new string Text
{
get
{
return base.Text.Replace(",", String.Empty);
}
set
{
base.Text = value;
}
}
}
What I don't like about it is that I know Text is a dependency property and we're overriding it, but surprisingly we can still bind to it in XAML:
<this:NumericTextBox x:Name="textBox"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=SomeText, Converter={StaticResource debugConverter}}" />
Then in C# when we call textBox.Text we do get the values without commas.
What do you guys think?
Perhaps you should add your class as an owner of the dependency property and override the getter and setter there:
public class NumericTextBox : TextBox
{
public NumericTextBox() { }
public static readonly DependencyProperty NumericTextProperty = TextBox.TextProperty.AddOwner(typeof(NumericTextBox), new PropertyMetadata(null));
public new string Text
{
get { return ((string)this.GetValue(NumericTextProperty )).Replace(",", String.Empty); }
set { this.SetValue(NumericTextProperty , value); }
}
}
You also have the possibility of overriding the metadata of the dependency property to hook in a custom validation callback method.
You approach doesn't work, because WPF doesn't actually use the class properties to change the value, but the dependency property system. It simply calls the SetValue method as you do in your property setter. You can try it out by setting a breakpoint in the setter, and changing the bound property in the gui. The setter breakpoint will never be hit. But you can hook into the events provided by the dependency property metadata.

Binding new property on Custom Control to View Model

How do i extend an existing control (ComboBox in my case) to include a new property which i can bind to a property on my view model??
I have a Dependancy Property on the control's class as follows:
public class MyComboBox : ComboBox
{
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(string), typeof(MyComboBox));
public string MyText
{
get
{
return GetValue(MyComboBox.MyTextProperty).ToString();
}
set
{
SetValue(MyComboBox.MyTextProperty, value);
}
}
And want to bind to it declaratively from XAML like this:
<MyComboBox MyText="{Binding MyTextOnViewModel,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
The Binding just won't work, any ideas why??
Thanks.
Your getter and setter reference TestTextProperty while the property is declared as MyTextProperty.
Your getter should also be casting instead of calling .ToString()
return (string)GetValue(MyTextProperty);
See this page for more complete instructions.

WPF: How to bind to a nested property?

I can bind to a property, but not a property within another property. Why not? e.g.
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"...>
...
<!--Doesn't work-->
<TextBox Text="{Binding Path=ParentProperty.ChildProperty,Mode=TwoWay}"
Width="30"/>
(Note: I'm not trying to do master-details or anything. Both properties are standard CLR properties.)
Update: the problem was that my ParentProperty depended on an object in XAML being initialized. Unfortunately that object was defined later in the XAML file than the Binding, so the object was null at the time when my ParentProperty was read by the Binding. Since rearranging the XAML file would screw up the layout, the only solution I could think of was to define the Binding in code-behind:
<TextBox x:Name="txt" Width="30"/>
// after calling InitializeComponent()
txt.SetBinding(TextBox.TextProperty, "ParentProperty.ChildProperty");
You can also set DataContext for TextBox in XAML (I don't know if it's optimal solution, but at least you don't have to do anything manually in codeBehind except of implementing INotifyPropertyChanged). When your TextBox has already DataContext (inherited DataContext) you write code like this:
<TextBox
DataContext="{Binding Path=ParentProperty}"
Text="{Binding Path=ChildProperty, Mode=TwoWay}"
Width="30"/>
Be aware that until your DataContext for TextBox isn't ready binding for Text property will not be 'established' - you can add FallbackValue='error' as Binding parameter - it will be something like indicator which will show you if binding is OK or not.
All I can think of is that the ParentProperty is being changed after the Binding is created, and it does not support change notification. Every property in the chain must support change notification, whether it be by virtue of being a DependencyProperty, or by implementing INotifyPropertyChanged.
Do both the ParentProperty and your class implement INotifyPropertyChanged?
public class ParentProperty : INotifyPropertyChanged
{
private string m_ChildProperty;
public string ChildProperty
{
get
{
return this.m_ChildProperty;
}
set
{
if (value != this.m_ChildProperty)
{
this.m_ChildProperty = value;
NotifyPropertyChanged("ChildProperty");
}
}
}
#region INotifyPropertyChanged Members
#endregion
}
public partial class TestClass : INotifyPropertyChanged
{
private ParentProperty m_ParentProperty;
public ParentProperty ParentProperty
{
get
{
return this.m_ParentProperty;
}
set
{
if (value != this.m_ParentProperty)
{
this.m_ParentProperty = value;
NotifyPropertyChanged("ParentProperty");
}
}
}
}
public TestClass()
{
InitializeComponent();
DataContext = this;
ParentProperty = new ParentProperty();
ParentProperty.ChildProperty = new ChildProperty();
#region INotifyPropertyChanged Members
#endregion
}

Setting Custom Properties in UserControl via DataBinding

Say I have a very simple UserControl that - for all intents and purposes - is nothing more than TextBox:
public partial class FooBox : UserControl
{
public static readonly DependencyProperty FooTextProperty =
DependencyProperty.Register("FooText", typeof(string), typeof(FooBox));
public FooBox()
{
InitializeComponent();
}
public string FooText
{
get { return textBlock.Text; }
set { textBlock.Text = value; }
}
}
<UserControl x:Class="Namespace.FooBox"
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="textBlock" />
</Grid>
</UserControl>
On the form it's declared as:
<local:FooBox FooText="{Binding Name}" />
The form's DataContext is set to an object that has a Name property. But this is not working for me. What am I missing?
The "get" and "set" parts of a property declaration in a DependencyProperty aren't actually called by the databinding system of WPF - they're there essentially to satisfy the compiler only.
Instead, change your property declaration to look like this:
public string FooText
{
get { return (string)GetValue(FooTextProperty); }
set { SetValue(FooTextProperty, value); }
}
... and your XAML to:
<UserControl ...
x:Name="me">
<Grid>
<TextBlock Text="{Binding FooText,ElementName=me}" />
</Grid>
</UserControl>
Now your TextBox.Text simply binds directly to the "FooText" property, so you can in turn bind the FooText property to "Name" just like you're currently doing.
Another way is to bind TextBlock.Text to a RelativeSource binding that finds the FooText property on the first ancestor of type "FooBox", but I've found that this is more complex than just giving the control an internal x:Name and using element binding.
Turns out the real problem is I was expecting the WPF framework to set my public property whereupon my code would respond to the changes and render according to the new value. Not so. What WPF does is call SetValue() directly and completely circumvents the public property. What I had to do was receive property change notifications using DependencyPropertyDescriptor.AddValueChanged and respond to that. It looks something like (inside the ctor):
var dpd = DependencyPropertyDescriptor
.FromProperty(MyDependencyProperty, typeof(MyClass));
dpd.AddValueChanged(this, (sender, args) =>
{
// Do my updating.
});

Resources