I have a highly customized Edit control which inherits RichTextBox. I needed a way to bind a Value to this control, so I registered a new DependencyProperty, but I have trouble to code it like I need.
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(XliffRichCellEditor),
new PropertyMetadata(new PropertyChangedCallback(XliffRichCellEditor.OnValuePropertyChanged)));
public String Value
{
get { return (String)this.GetValue(ValueProperty); }
set { this.SetValue(ValueProperty, value); }
}
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Need to change Document in RichTextBox when Binding Source is changed
// But also ignore if the change comes from RichTextBox which is only updating
// the DependencyProperty. In this case Binding Source should be updated.
}
Please help.
use can use UpdateSourceTrigger=Explicit in your Binding statement and get the control of property updation in your hand.
Check this Thread
Related
I created a user control and wanted to get the value of the DependencyProperty "ListBoxReadOnly" in the code. I set the value in the XAML:
<control:AutoCompleteTextBox x:Name="actbFullName" ListBoxReadOnly="True"/>
When I tried to read the value in the constructor, it only shows the default value which is false.
I tried to get the value via a callback back but probably I am lacking some understanding of the whole framework. Since the callback is a static method, I cannot apply it to the instance of my user control.
public static readonly DependencyProperty ListBoxReadOnlyDependency =
DependencyProperty.Register("ListBoxReadOnly", typeof(bool),
typeof(AutoCompleteTextBox), FrameworkPropertyMetadata
(false, FrameworkPropertyMetadataOptions.AffectsRender));
public bool ListBoxReadOnly
{
get
{
return (bool) GetValue(ListBoxReadOnlyDependency);
}
set
{
SetValue(ListBoxReadOnlyDependency, value);
}
}
// constructor of user control
public AutoCompleteTextBox()
{
InitializeComponent();
// *** shows "false" (default value) even though set to true in XAML
// *** see XAML above ***
var test = ListBoxReadOnly;
}
Any help is appreciated :-)
I would expect your code (as is) to show false. The DP is initialized to false. In the constructor of your control, neither the default control style, nor the properties set in xaml have been applied yet.
The style is only applied after OnApplyTemplate() is called (unless you force it).
If you want to track DP changes, you need a DP change handler.
When I tried to read the value in the constructor, it only shows the default value which is false.
The property can't be set before the control has been initialized.
Since the callback is a static method, I cannot apply it to the instance of my user control.
You could cast the DependencyObject to the type of your control in the callback:
public static readonly DependencyProperty ListBoxReadOnlyDependency =
DependencyProperty.Register("ListBoxReadOnly", typeof(bool),
typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata
(false, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnChanged)));
private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteTextBox ctrl = (AutoCompleteTextBox)d;
var x = ctrl.ListBoxReadOnly;
//...
}
I have a WPF control that is based on the TextBox control:
public class DecimalTextBox : TextBox
I have a dependency property that is bound to, which manages the numeric value, and is responsible for setting the Text property:
public decimal NumericValue
{
get { return (decimal)GetValue(NumericValueProperty); }
set
{
if (NumericValue != value)
{
SetValue(NumericValueProperty, value);
SetValue(TextProperty, NumericValue.ToString());
System.Diagnostics.Debug.WriteLine($"NumericValue Set to: {value}, formatted: {Text}");
}
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
if (decimal.TryParse(Text, out decimal num))
{
SetValue(NumericValueProperty, num);
}
}
This works well when entering a value into the textbox itself (it updates the underlying values, etc...). However, when the bound property of NumericValue is changed, despite updating the NumericValue DP, the Text property is not updated. In the tests that I've done, it would appear that the reason for this is that the set method above is not called when the bound value is updated. The binding in question looks like this:
<myControls:DecimalTextBox NumericValue="{Binding Path=MyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Can anyone point me in the right direction as to why this property setter is not firing, or is there a better way to approach this?
As explained in Custom Dependency Properties and XAML Loading and Dependency Properties, you should not call anything else than GetValue and SetValue in the CLR wrapper of a dependency property:
Because the current WPF implementation of the XAML processor behavior for property setting bypasses the wrappers entirely, you should not put any additional logic into the set definitions of the wrapper for your custom dependency property. If you put such logic in the set definition, then the logic will not be executed when the property is set in XAML rather than in code.
In order to get notified about value changes, you'll have to register a PropertyChangedCallback with the dependency property metadata.
public static readonly DependencyProperty NumericValueProperty =
DependencyProperty.Register(
"NumericValue", typeof(decimal), typeof(DecimalTextBox),
new PropertyMetadata(NumericValuePropertyChanged));
public decimal NumericValue
{
get { return (decimal)GetValue(NumericValueProperty); }
set { SetValue(NumericValueProperty, value); }
}
private static void NumericValuePropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var textBox = (DecimalTextBox)obj;
textBox.Text = e.NewValue.ToString();
}
The WPF binding is not actually using your getter and setter, but instead directly interacts with the dependency property NumericValueProperty. In order to update the text, subscribe to the PropertyChanged event of the NumericValueProperty instead of trying to do anything special in the setter.
Subscribe to the change in your DependencyProperty definition, similar to the following:
// Using a DependencyProperty as the backing store for NumericValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NumericValueProperty =
DependencyProperty.Register("NumericValue", typeof(decimal), typeof(DecimalTextBox), new FrameworkPropertyMetadata(0.0m, new PropertyChangedCallback(OnNumericValueChanged)));
private static void OnNumericValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = d as DecimalTextBox;
// if the new numeric value is different from the text value, update the text
}
I'm trying to replace the SelectedText of a TextBox with a new value by binding on the custom property 'Selected'. Currently, updating Selected through binding doesn't change the actual SelectedText. I'm almost there I think; at least mouse-selecting text is updating Selected.
I'd prefer solutions based on inheriting from TextBox if possible.
Can anybody tell me what's missing please?
class SelectionTextbox : TextBox
{
public static readonly DependencyProperty SelectionProperty = DependencyProperty.Register("Selection", typeof(string), typeof(SelectionTextbox));
public string Selection
{
get
{
return (string)base.GetValue(SelectionProperty);
}
set
{
base.SetValue(SelectionProperty, value);
}
}
protected override void OnSelectionChanged(RoutedEventArgs e)
{
base.OnSelectionChanged(e);
Selection = SelectedText;
}
}
The problem is, that you never actually do anything with the value you assign to Selection. You need to actually make it the selected text.
public string Selection
{
get
{
return (string)base.GetValue(SelectionProperty);
}
set
{
base.SetValue(SelectionProperty, value);
if(value != SelectedText)
SelectedText = value;
}
}
For Binding to update the source you have to specify Mode=TwoWay if you want to reflect changes back to code. This can be done by two ways:
Selection="{Binding Path=MyProperty, Mode=TwoWay}"
or by
public static readonly DependencyProperty SelectionProperty =
DependencyProperty.Register("Selection",
typeof(string),
typeof(SelectionTextbox),
new FrameworkPropertyMetadata(default(string),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
By using the second method you have that all bindings to Selection are done TwoWay and you do not have to specify it explicitly.
Ok, so I'm trying to run some code that modifies a UI when a user changes a custom control's dependency property value in design mode; but only when in design mode.
I've tried these approaches:
1.
public static DependencyProperty x = ...Register(..., new PropertyMetadata(null, changeMethod));
2.
set { SetValue(XProp, value); changeMethod(value); }
3.
var observable = x as INotifyPropertyChanged;
observable.PropertyChanged += ObservablePropertyChanged;
But all of them seem to have their own issues in that they either trigger errors or don't work at all.
So does anyone know what the correct way to listen to a dependency property change in design mode is, and if so can you give an example?
The right way to handle DependencyProperty changes is to:
. Declare the DependencyProperty:
public static DependencyProperty MyXProperty;
. Create the public get/set Property:
public string MyX
{
get { return (string)GetValue(MyXProperty); } //Supposing that the property type is string
set { SetValue(MyXProperty, value); }
}
. Register the DependencyProperty in your static constructor:
static MyClass()
{
MyXProperty= DependencyProperty.Register("MyX", typeof(string), typeof(MyClass), new FrameworkPropertyMetadata("", OnMyXPropertyChanged));
}
. Declare the Property Changed Method:
private static void OnMyXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyClass thisClass = d as MyClass ;
//Do Something
}
Please provide more information if you still can't find your solution.
I'm trying to develop a custom tri-state button user control and so far I've been using CTF to set properties.
But I would like to change this to be using the WPF property system with PropertiesDependencies.
Unfortunately I don't manage to make it work, when I set the property from my xaml (father) using a DynamicResource, the value is not set.
<common:StateImageButton x:Name="story_buttonRecord" BackTest="{DynamicResource backTest}" />
Here is the code I have in my button controller :
public ImageSource BackTest
{
get { return (ImageSource)this.GetValue(BackProp); }
set { this.SetValue(WidthProp,value); }
}
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata());
I don't even use the property in my button xaml yet, but it apparently doesn't even enter in the Setter. I've been searching a lot online without success. So maybe I'm missing something .
Thanks in advance for your help,
Boris
Also, WPF doesn't use the setter provided to set a property, it does it directly.
The way to debug when WPF sets a property is to add a callback for when the property is set, like so.
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata(OnBackChanged));
private static void OnBackChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var sender = (StateImageButton)d; // Put a breakpoint here
}