Why does PropertyChangedCallback method not execute from Dependency Property OverrideMetadata? - wpf

I have a class called CustomGrid which derives from the Grid class. I am attempting to run a method when there are changes made to the grid's parent window's title by using OverrideMetadata on the Window class's TitleProperty. My approach to this problem, however, does not seem to work despite having another PropertyChangedCallback method I implemented, that works, using the same approach (OverrideMetadata) for the grid's MarginProperty:
public class CustomGrid : Grid
{
static CustomGrid()
{
Type ownerType = typeof(CustomGrid);
MarginProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMarginPropertyChanged)));
Window.TitleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnTitlePropertyChanged)));
}
private static void OnMarginPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// This executes when the grid's margin changes.
}
private static void OnTitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// This does not execute when the parent window's title changes.
}
}
Why does the OnTitlePropertyChanged method not execute when the grid's parent window's title is changed? Thanks.

The callback method is not called because you did not set the Window.Title property on a CustomGrid instance.
The expression
Window.TitleProperty.OverrideMetadata(
typeof(CustomGrid),
new FrameworkPropertyMetadata(OnTitlePropertyChanged));
registers the OnTitlePropertyChanged callback for the type CustomGrid. This means the callback is called whenever the dependency property is set on instances of CustomGrid, but only on those instances, not any objects like e.g. the MainWindow.

Related

Another WPF Set focus problem with Button Click (control not a child at design time)

I have a button on a WPF window that adds a tabitem to a tabcontrol on the window. A user control that fills that tabitem is also created in that event. I want to set the focus to a textbox on that user control. I've tried all kinds of txt.Focus code and so forth but the button always still have focus after the click event is executed.
I can't use this as the textbox is not part of the xaml on this window at design time.
MyAttachedProps:EventFocusAttachment.ElementToFocus="{Binding ElementName=NotAvailableAtDesignTime}"
The only thing I can think of is a timer to execute after the button click but there has to be a better way.
You could use a bool attached dependency property.
Bind this to a public bool property in your viewmodel.
Set that to true when you want to focus the control.
I have a bit of code. Can't recall if I wrote it or grabbed it off the web. And I can't recall actually using it either.
public static class FocusExtension
{
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(FocusExtension),
new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
private static async void OnIsFocusedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
if ((bool)e.NewValue)
{
await Task.Delay(200);
uie.Focus();
Keyboard.Focus(uie);
}
}
}
This the await task delay introduces a 200ms wait so other stuff can finish whatever it's doing. You could instead defer the focussing using dispatcher.
Application.Current.Dispatcher.InvokeAsync(new Action(() =>
{
uie.Focus();
Keyboard.Focus(uie);
}), DispatcherPriority.ContextIdle);
Due to closures, that code will capture whatever uie is so long as it's in scope.

Add logic to control with DependencyProperty

I need to add some logic to user control with DependencyProperty.
My logic is supposed to change properties on controls inside my UserControl.
I want to avoid building huge "dependency tree" because I have a lot of user controls. I just want to use binding in my windows (not in nested user controls).
This is my control:
public partial class BucketElevatorControl : UserControl
{
public BucketElevatorControl()
{
InitializeComponent();
}
public bool On
{
get
{
return (bool)GetValue(OnProperty);
}
set
{
SetValue(OnProperty, value);
}
}
// Using a DependencyProperty as the backing store for IsOn. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OnProperty = DependencyProperty.Register(
"On",
typeof(bool),
typeof(BucketElevatorControl),
new PropertyMetadata(
false, PropertyChangedCallback
));
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
// I want to do something with my UserControl child controls
}
}
The question is: how can I do some logic in contol code behind and take advantage of data binding?
My logic is complicated (drawing graphics, animations etc.).
You should create CoerceValueCallbacks for the properties you want to change. Those callbacks set the new values. When this property changes, you then coerce the others, like so:
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
dependencyObject.CoerceValue(MinReadingProperty);
dependencyObject.CoerceValue(MaxReadingProperty);
}
I have no idea what you mean by "dependency tree", but if you want to alter the state of stuff in your template according to changes in your control's dependency properties, you can do that with TemplateBinding and/or triggers in your control template. Write value converters if you need to. Most of what you need to do can probably be done that way.
If you need more complicated logic, you can also override OnApplyTemplate() in your control, and call GetTemplateChild() to get named controls within the control's template. For example, you might require the template to have a TextBox somewhere in it called PART_FooText; throw an exception if you get null from GetTemplateChild("PART_FooText") as TextBox. If the TextBox is there, do anything you like to it: Handle events, set properties, etc. If you like, keep a private field TextBox _PART_FooText; to fiddle with it later on, in your property-changed callbacks, other events, or whatever.

Notify if xaml calls SetValue() of a Dependency Property

I want to draw lines in UserControls that are in a ListBox. The number of lines is a Dependency Property and is set via Xaml Style. If the property has changed, I want to draw the lines. But Setters aren't called, if property is changed by xaml. Xaml calls SetValue() itself. But I need to know, when this property is changed to call my function for drawing the lines. If I call this function in the constructor, the property isn't bound yet. Can anyone help me please.
You can add PropertyChanged callback to your DependencyProperty declaration like
public static readonly DependencyProperty LineCountProperty = DependencyProperty.Register(
"LineCount",
typeof(int),
typeof(Window),
new FrameworkPropertyMetadata(
0,
new PropertyChangedCallback(OnLineCountChanged)
)
);
private static void OnLineCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Here you call you function on `d` by typecasting it into your class
}

Co-opting Binding to listen to PropertyChanged events without a FrameworkElement

I have some nested view models that implement INotifyPropertyChanged. I'd like to bind an event listener to a nested property path (e.g. "Parent.Child.Name"), much like FrameworkElement dependency properties can be bound to arbitrary nested properties.
However, I just want something like a PropertyChanged event listener -- I don't actually have any UI element I'd like to bind. Is there any way to use the existing framework to set up such an event source? Ideally, I shouldn't need to modify my view model classes (as this is not required for regular data binding in Silverlight).
You can certainly co-opt the binding/dependency-property infrastructure to listen for changes to a nested property. The code below is WPF but I believe you can do something similar in Silverlight:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new Parent { Child = new Child { Name = "Bob" } };
this.SetBinding(ChildNameProperty, new Binding("Child.Name"));
}
public string ChildName
{
get { return (string)GetValue(ChildNameProperty); }
set { SetValue(ChildNameProperty, value); }
}
// Using a DependencyProperty as the backing store for ChildName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ChildNameProperty =
DependencyProperty.Register("ChildName", typeof(string), typeof(MainWindow), new UIPropertyMetadata(ChildNameChanged));
static void ChildNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("Child name is now " + e.NewValue);
}
}
So I've defined my own DependencyProperty, not part of any UI per se (just the MainWindow class), and bound "Child.Name" to it directly. I'm then able to be notified when Child.Name changes.
Will that work for you?

wpf how to tell when databinding has finished?

I've got a custom control which has a DependencyProperty MyAnimal - I'm binding an Animal Property on my ViewModel to the MyAnimal DependencyProperty.
I've stuck a TextBox on the Control so I can trigger an Event - whenever I trigger the event the MyAnimal property has been set - however if I put a break point on the Setter of the MyAnimal property it never gets fired!
I guess I'm missing something fundamental about WPF Dependency Properties/Binding?!
And so my question is, if I can't use the Setter how can I find out when its been set? If I put if I put a break point after InitializeComponent() its null and I had a look to see if theres an Event a can hook up to - DatabindingFinished or similar? but can't see what it would be ...
Can anyone assist please?
Thanks,
Andy
public partial class ControlStrip
{
public ControlStrip()
{
InitializeComponent();
}
public Animal MyAnimal
{
get
{
return (Animal)GetValue(MyAnimalProperty);
}
set
{
SetValue(MyAnimalProperty, value);
}
}
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip));
private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
var myAnimal = MyAnimal;
MessageBox.Show(myAnimal.Name);
}
}
The setter methods are never called by the runtime. They go directly to the DependencyProperty. You will need to add an additional argument to your call to RegisterAttached(). There you can add a PropertyChangedCallback.
Here is some sample code:
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip), new PropertyMetadata(AnimalChanged));
private static void AnimalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
// Do work here
}
The setter is only there for your use - you actually can leave the property off entirely, since DataBinding uses the actual DependencyProperty itself, not the CLR property.
If you need to see when the property changes, you will need to specify PropertyMetadata on your dependency property, and provide a PropertyChangedCallback.
For details, I recommend reading Dependency Property Metadata.

Resources