I have the following dependency property:
public bool UndoZoom
{
get { return (bool)GetValue(UndoZoomProperty); }
set { SetValue(UndoZoomProperty, value); }
}
// Using a DependencyProperty as the backing store for UndoZoom. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UndoZoomProperty =
DependencyProperty.Register("UndoZoom", typeof(bool), typeof(ZoomBehavior), new PropertyMetadata(false, new PropertyChangedCallback(OnUndoZoomChanged)));
On the callback methods I change this property to false:
private static void OnUndoZoomChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ZoomBehavior zoomBehavior = sender as ZoomBehavior;
if (zoomBehavior == null || zoomBehavior.UndoZoom == false)
return;
//DO SOMETHING...
zoomBehavior.UndoZoom = false;
//ALSO TRY: zoomBehavior.SetValue(UndoZoomProperty, false);
}
The dependency property changes well, but the property that binding to it not!
The binding look like that :
UndoZoom="{Binding MyClass.UndoZoom,Mode=TwoWay}"
I would like to note that the binding does work, when I change the property in the model, the callback is fire, that's mean that the dependency property changes.
I just do not understand why it does not work the other way too, I expect that when I change the dependency property, the property in the model will also change.
I would love help.
The coercion callback is more suited to doing this. The property changed callback is meant for reacting to a change of value. The Coercion callback is for making sure the value is valid based on the current state which feels more like what you are doing here.
Related
I have a Template Control which has a StackPanel as it's root. What I want is a way to make something like this:
<Controls:MyControl Kind="SomeKind"/>
And based on SomeKind the StackPanel's background would change. There would be a limited number of "Kinds", the same way there is a limited number of HorizontalAlignments in a Button, for example.
<Button HorizontalAlignment="Center"/>
I've searched in the internet a bit and it does seems like it involves Attached Properties, but I haven't found a clean, simple and easy-to-follow example for UWP. I've found some examples for WPF but they doesn't seem to work.
No you don't need attached properties since it's likely to be only associated within your custom control. What you need is a dependency property of an enum type.
Say if you have this enum -
public enum PanelBackgroundType
{
Orange,
Pink,
Offwhite
}
Then your dependency property will look something like this -
public PanelBackgroundType PanelBackgroundType
{
get { return (PanelBackgroundType)GetValue(PanelBackgroundTypeProperty); }
set { SetValue(PanelBackgroundTypeProperty, value); }
}
// Using a DependencyProperty as the backing store for PanelBackgroundType. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PanelBackgroundTypeProperty =
DependencyProperty.Register("PanelBackgroundType", typeof(PanelBackgroundType), typeof(MyControl),
new PropertyMetadata(PanelBackgroundType.Offwhite, (s, e) =>
{
if ((PanelBackgroundType)e.NewValue != (PanelBackgroundType)e.OldValue)
{
// value really changed, invoke your changed logic here
var control = (MyControl)s;
switch ((PanelBackgroundType)(e.NewValue))
{
case PanelBackgroundType.Orange:
control.MyStackPanel.Background = new SolidColorBrush(Colors.Orange);
break;
case PanelBackgroundType.Pink:
control.MyStackPanel.Background = new SolidColorBrush(Colors.Pink);
break;
case PanelBackgroundType.Offwhite:
default:
control.MyStackPanel.Background = new SolidColorBrush(Colors.Wheat);
break;
}
}
else
{
// else this was invoked because of boxing, do nothing
}
}));
Note that I have a check (PanelBackgroundType)e.NewValue != (PanelBackgroundType)e.OldValue inside the property changed callback to see if the value of the dp really has changed. This may seem redundant but according to MSDN, this is the best practise as -
If the type of a DependencyProperty is an enumeration or a structure,
the callback may be invoked even if the internal values of the
structure or the enumeration value did not change. This is different
from a system primitive such as a string where it only is invoked if
the value changed. This is a side effect of box and unbox operations
on these values that is done internally. If you have a
PropertyChangedCallback method for a property where your value is an
enumeration or structure, you need to compare the OldValue and
NewValue by casting the values yourself and using the overloaded
comparison operators that are available to the now-cast values. Or, if
no such operator is available (which might be the case for a custom
structure), you may need to compare the individual values. You would
typically choose to do nothing if the result is that the values have
not changed.
Have a look at this link: https://msdn.microsoft.com/en-us/windows/uwp/xaml-platform/custom-dependency-properties
It will show you how to add custom dependency properties for an object that you'll be able to edit in the UI.
I'll give you a quick example of what you want event though I recommend you to take a look at Microsoft's docs
public sealed partial class MyControl : UserControl
{
public MyControl()
{
this.InitializeComponent();
}
public static readonly DependencyProperty KindProperty = DependencyProperty.Register(
"Kind", typeof(string), typeof(MyControl),
new PropertyMetadata(null, new PropertyChangedCallback(OnKindChanged)));
public string Kind
{
get { return (string)GetValue(KindProperty); }
set { SetValue(KindProperty, value); }
}
private static void OnKindChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Executed method when the KindProperty is changed
}
}
In a WPF application built by the MVVM principle, I need to explicitly set the focus to a TextBox from code (reacting on a keyboard event), and also know whether focus has been lost. From another question here I have gathered that appearently the way to do this is with data binding on a DependencyProperty. For that I have picked up the following code:
public static class FocusHelper
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof(bool), typeof(FocusHelper),
new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
private static void OnIsFocusedPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
if ((bool)e.NewValue)
{
uie.Focus();
}
}
}
The TextBox binding looks like this:
<TextBox Text="{Binding Path=RowData.Row.Group}" helper:FocusHelper.IsFocused="{Binding RowData.Row.GroupFocused, Mode=TwoWay}"
This is in a (DevExpress) grid; Row is the actual ViewModel the entire row is bound to.
The corresponding code in the bound ViewModel:
private bool groupFocused;
public bool GroupFocused
{
get { return this.groupFocused; }
set
{
this.groupFocused = value;
this.NotifyOfPropertyChange(() => this.GroupFocused);
}
}
When the keyboard event is handled, GroupFocused is set to true, which sure enough invokes the DependencyProperty callback and sets the focus to the TextBox. When the control loses focus, however, that change is not reflected back on the ViewModel (the DependencyProperty's callback is also not invoked).
Is there any obvious reason for this behavior? Anything wrong with the code?
(I have tried adding UpdateSourceTrigger with both PropertyChanged and LostFocus to the binding, also changing the DependencyProperty's default value to true, none of which changed anything about the behavior. I also tried IsKeyboardFocused instead of IsFocused with no change, and IsKeyboardFocusWithin, which made the application close with no comment - likely a DevExpress exception - on assembling the grid.)
You are not data binding your GroupFocused property to the TextBox.IsFocused property, you are data binding it to the FocusHelper.IsFocused property, which programmatically calls Focus on the TextBox.
There's a distinct difference. Calling the Focus method on the TextBox will result in the TextBox.IsFocused property being set to true, but there is no connection between that property and either your GroupFocused or your FocusHelper.IsFocused properties, so neither will be set to false when the TextBox.IsFocused property is set to false.
Furthermore, you cannot data bind to the TextBox.IsFocused property in an attempt to set the focus because it is read only. See the UIElement.IsFocused Property page on MSDN for more information on that.
However, there is a simple solution. It might not look pretty, but it will certainly work... just set the GroupFocused property to false before you set it to true each time. Perhaps something like this:
private void FocusTextBox()
{
GroupFocused = false;
GroupFocused = true;
}
...
FocusTextBox();
Here is my problem. I recently created a custom control, which works pretty well.
But i have a problem when i use it, i have a little problem :
In my control, i made a property named Value, defined like this :
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), new PropertyMetadata(1000));
public int Value
{
get
{
return (int)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
this.ValueText.Text = value.ToString();
}
}
When I do a databinding to this value, the binding works, but the default value is set to 1000, so it first print 1000. But actually, the property bound to Value isn't equal to 1000.
I would like to print in ValueText.Text the value of the bound property when the Value property is created.
Edit : Question is simple, how can I remove that default value and directly print the bound property ?
You should be able to setup a PropertyChanged event in your DependancyProperties metadata to update ValueText when Value changes.
somthing like this:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown),
new PropertyMetadata(1000, (sender, e) => (sender as NumericUpDown).ValueText.Text = e.NewValue.ToString()));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
The property setter will not get called as things change via WPF's data binding, so this technique will not work.
The default, initial value will always be 1000, but data binding may override it. You will need to add a Callback to appropriately notify you when the dependency property value is changed.
For details, see the Dependency Property Callbacks page to see how to implement a property changed callback correctly. This is the appropriate place to set your other (ValueText) property.
There are plenty of ways to bind a SOURCE method to target property, either by ValueConverter or by ObjectDataProvider. However, what if I want to have the binding affect the target METHOD?
Consider the following example:
class ListBoxViewModel
{
public static readonly DependencyProperty CurrentItemProperty = DependencyProperty.Register("CurrentItem", typeof (object), typeof (ListBoxViewModel));
public object CurrentItem
{
get { return (object) GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
}
I'd like to bind the property CurrentItem to ListBox's CollectionView. However, since the CurrentItem property of CollectionView is read-only, I can't bind to it directly. Instead, I have to execute MoveCurrentToPosition function. How can I do it?
If there is a different way to do that - Without binding to a method, I'd love to hear it too, however, the main question is how to bind to a method, if not in this case, then in a similar one. If it is impossible, what is the best alternative? E.g one idea that comes to mind is subscribing to the change notification of the dependency property (CurrentItem in this case) and running the procedural code from that function.
Thanks!
You can register your property with a property changed callback in which you then can update the CollectionView manually:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register
(
"CurrentItem",
typeof(object),
typeof(ListBoxViewModel),
new UIPropertyMetadata(null, CurrentItemChanged)
);
public object CurrentItem
{
get { return (object)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
private static void CurrentItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Update current item logic
}
I may be doing this all wrong... so hang with me
I am making a user control with a property which the user can bind to. The in setter for the property, I bind the PropertyChanged listener to the property so I can react to changes to its state. The code behind for this user control looks like this:
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register("Node", typeof(MockRequirementWrapper), typeof(RecNode2));
public MockRequirementWrapper Node
{
get
{
return (MockRequirementWrapper)GetValue(NodeProperty);
}
set
{
if(Node != null)
Node.PropertyChanged -= Update;
SetValue(NodeProperty, value);
Node.PropertyChanged += new PropertyChangedEventHandler(Update);
OnPropertyChanged(this, "Node");
}
}
then, in another user control, I bind to this property a node I've created elsewhere like this:
<local:RecNode2 Node="{Binding}"/>
What I am finding is the recnode exists and is bound to a node... but if I put a breakpoint in the setter, it never gets called. Am I misunderstanding how the binding works? How do I add my listener when the node changes?
The framework will always call GetValue and SetValue directly, the property is just for convenience and sould never contain logic besides those calls.
If you want to do something on changes register a PropertyChangedCallback in the Metadata when registering the DependencyProperty.
Taken from http://msdn.microsoft.com/en-us/library/ms753358.aspx:
public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}