I have a usercontrol in which i want to expose a property called ExpressionText and in the
xaml a binding can be defined to this property.
So i created a dependency property
public static readonly DependencyProperty EditorText =DependencyProperty.Register("EditorText", typeof(string), typeof(MyUerControl));
and
public string ExpressionText
{
get
{
return (string)GetValue(EditorText);
}
set
{
SetValue(EditorText, value);
}
}
in the xaml i do this.
<controls:MyUerControl x:Name="textEditor" ExpressionText="{Binding
Path=Expression,Mode=TwoWay}" />
but i get
A binding cannot be set on ExpressionText property of type MyUserControl. Binding can be set
only on a depenedecy property of type Dependency object error.
Is there something wrong in my approach ? How do i solve this problem ?
This should work:
public static DependencyProperty EditorTextProperty = DependencyProperty.Register("ExpressionText", typeof(string), typeof(MyUserControl),
new PropertyMetadata(new PropertyChangedCallback((s, e) =>
{ })));
public string ExpressionText
{
get
{
return (string)base.GetValue(EditorTextProperty);
}
set
{
base.SetValue(EditorTextProperty, value);
}
}
You are defining EditorText as the name of your DependencyProperty. That is the name that is available publicly for you to bind to. If you want it to be called ExpressionText, then you need to register that as the name.
public static readonly DependencyProperty EditorText =
DependencyProperty.Register("ExpressionText", typeof(string), typeof(MyUerControl));
Related
I created an Interaction.Behavior behavior that needs to receive a variable amount of input.
For this, the behavior has a List<> Dependency property to receive content:
private static readonly DependencyPropertyKey FocusTargetsPropertyKey = DependencyProperty.RegisterReadOnly("Targets", typeof(List<FocusTarget>), typeof(StatefulFocusManagerBehavior), new PropertyMetadata(new List<FocusTarget>()));
public static readonly DependencyProperty FocusTargetsProperty = FocusTargetsPropertyKey.DependencyProperty;
public List<FocusTarget> Targets
{
get => (List<FocusTarget>)this.GetValue(FocusTargetsProperty);
set => this.SetValue(FocusTargetsProperty, value);
}
And the content is implemented as a class FocusTarget that derives from FrameworkElement:
public class FocusTarget : FrameworkElement
{
#region DepProp: FocusTarget
public static readonly DependencyProperty FocusTargetProperty = DependencyProperty.Register("Target", typeof(FrameworkElement), typeof(FocusTarget), new PropertyMetadata(null));
public FrameworkElement Target
{
get => (FrameworkElement)this.GetValue(FocusTargetProperty);
set => this.SetValue(FocusTargetProperty, value);
}
#endregion
#region DepProp: StateName
public static readonly DependencyProperty StateNameProperty = DependencyProperty.Register("StateName", typeof(string), typeof(FocusTarget), new PropertyMetadata(null));
public string StateName
{
get => (string)this.GetValue(StateNameProperty);
set => this.SetValue(StateNameProperty, value);
}
#endregion
}
The Behavior is declared as follows:
<b:Interaction.Behaviors>
<behav:StatefulFocusManagerBehavior FocusTarget="{Binding ElementName=txtResponse}">
<behav:StatefulFocusManagerBehavior.Targets>
<behav:FocusTarget Target="{Binding ElementName=txtResponse}" StateName="Text" />
<behav:FocusTarget Target="{Binding ElementName=QnAToggle}" StateName="Toggle"/>
</behav:StatefulFocusManagerBehavior.Targets>
</behav:StatefulFocusManagerBehavior>
</b:Interaction.Behaviors>
Now there is what works:
The behav:StatefulFocusManagerBehavior has its FocusTarget property binding is working as expected
The behav:FocusTarget instances hast their property StateName set as expected
The behav:FocusTarget instances have their Target property always set to null
I did suspect this could be a DataContext issue but could not verify nor dismiss it, leaving me puzzled on the possible issue and solution.
I tried to set the DataContext but this binding to is not working and giving me null:
<behav:FocusTarget Target="{Binding ElementName=txtResponse}"
StateName="Text"
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}" />
Inheriting the data context and accessing elements from a behavior collection does not work that way, because the collection is not in the visual tree and not a FrameworkElement or Freezable that enable binding.
Change the FocusTargetsProperty to a FreezableCollection<FocusTarget> instead of a List<FocusTarget>. Furthermore, make sure that you assign a new instance of the collection in the constructor.
public class StatefulFocusManagerBehavior : Behavior<FrameworkElement>
{
private static readonly DependencyPropertyKey FocusTargetsPropertyKey = DependencyProperty.RegisterReadOnly("Targets", typeof(FreezableCollection<FocusTarget>), typeof(StatefulFocusManagerBehavior), new PropertyMetadata(null));
public static readonly DependencyProperty FocusTargetsProperty = FocusTargetsPropertyKey.DependencyProperty;
public FreezableCollection<FocusTarget> Targets
{
get => (FreezableCollection<FocusTarget>)this.GetValue(FocusTargetsProperty);
set => this.SetValue(FocusTargetsProperty, value);
}
public StatefulFocusManagerBehavior()
{
SetValue(FocusTargetsPropertyKey, new FreezableCollection<FocusTarget>());
}
}
Then, instead of inheriting from FrameworkElement in FocusTarget, derive from Freezable.
public class FocusTarget : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new FocusTarget();
}
// ...your other code.
}
I currently have a Dependency Property as such:
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyPropertyDefaults", typeof(ICollection<string>), typeof(MyPanel), new PropertyMetadata(new List<string>()));
public ICollection<string> MyProperty
{
get
{
return GetValue(MyPropertyProperty) as ICollection<string>;
}
set
{
this.SetValue(MyPropertyProperty, value);
}
}
The aim is that this subpanel will be passed a list via a binding, that the subpanel manipulates, and then the parent can read later. E.g.
<xaml:MyPanel MyProperty="{Binding MyPropertyList}" />
However, FxCop reports CollectionPropertiesShouldBeReadOnly and I need to remove the setter, which is required by the property. How do I fix this? What is the correct way to do what I am doing?
Declare the setter as private like this:
public class MyPanel : Panel
{
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyPropertyDefaults", typeof(ICollection<string>), typeof(MyPanel), new PropertyMetadata(new List<string>()));
public ICollection<string> MyProperty
{
get
{
return GetValue(MyPropertyProperty) as ICollection<string>;
}
private set
{
this.SetValue(MyPropertyProperty, value);
}
}
}
I have a UserControl that add a DependencyProperty for it .
public const string TextValuePropertyName = "TextValue";
public string TextValue
{
get
{
return (string)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
}
}
public static readonly DependencyProperty TextValueProperty = DependencyProperty.Register(
TextValuePropertyName,
typeof(string),
typeof(FormatUserControl),
new UIPropertyMetadata());
and use it in another Usercontrol
<local:FormatUserControl TextValue="{Binding Subject,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
When i use this don't set value for this property when i change Subject value?
Your FormatUserControl is the class and you should register the property for it not for the NumberFormatUserControl like this (I am not aware what is the relationship between the two user controls):
public static readonly DependencyProperty TextValueProperty = DependencyProperty.Register(
TextValuePropertyName,
typeof(string),
typeof(FormatUserControl),
new UIPropertyMetadata());
I have a ViewModel whose properties are bounded to from the View (XAML file).
I also have a property "StaticText" in the code behind file.
how can I access the property "StaticText" from inside the ViewModel ?
as suggested by Cameron, i've created a dependency property in my View :
String textToTest="I am just testing .";
public string TextToTest
{
get { return (string)this.GetValue(TextToTestProperty); }
set { this.SetValue(TextToTestProperty, value); }
}
public static readonly DependencyProperty TextToTestProperty =
DependencyProperty.Register("TextToTest", typeof(string),
typeof(MainWindow), new PropertyMetadata(false));
and I've added this to the constructor :
Binding aBinding = new Binding();
aBinding.Path = new PropertyPath("TextToTest");
aBinding.Source = viewModel;
aBinding.Mode = BindingMode.TwoWay;
this.SetBinding(TextToTestProperty, aBinding);
but I get an exception when I run the code.
By making the property a Dependency Property you can bind the property in the View to a property in the ViewModel.
public string TextToTest
{
get { return (string)this.GetValue(TextToTestProperty); }
set { this.SetValue(TextToTestProperty, value); }
}
public static readonly DependencyProperty TextToTestProperty =
DependencyProperty.Register("TextToTest", typeof(string),
typeof(MyControl), new PropertyMetadata(""));
See How to: Implement a Dependency Property
I would like to make it so that, as default, when I bind to one of my dependency properties the binding mode is two-way and update-trigger is property changed. Is there a way to do this?
Here is an example of one of my dependency properties:
public static readonly DependencyProperty BindableSelectionLengthProperty =
DependencyProperty.Register(
"BindableSelectionLength",
typeof(int),
typeof(ModdedTextBox),
new PropertyMetadata(OnBindableSelectionLengthChanged));
When registering the property, initialize your metadata with:
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
}
In the Dependency Property declaration it would look like this:
public static readonly DependencyProperty IsExpandedProperty =
DependencyProperty.Register("IsExpanded", typeof(bool), typeof(Dock),
new FrameworkPropertyMetadata(true,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnIsExpandedChanged));
public bool IsExpanded
{
get { return (bool)GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}