MyProperty not updated in PropertyChangedCallBack - c#

Is there a CallBack After PropertyChangedCallBack ? because in the PropertyChangedCallBack the change hasn't been made yet.
In the example below after I set MyProperty and when Foo() is being called, MyProperty still got the old value in Foo().
I want to be able to call Foo() just after I change MyProperty with the new value
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0, MyProperty_PropertyChanged));
private static void MyProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = (ownerclass)d;
d.Foo();
}
void Foo()
{
//-->old value of MyProperty
}

Related

Dependency Property command's CanExecute() not updating

I have a user control and within I defined the following property:
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string),
typeof(MyUserControlView), new PropertyMetadata(null, MyPropertyChangedCallback));
private static void MyPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (MyUserControl) d;
control.MyProperty = (string)e.NewValue;
}
and the following command:
public ICommand MyCommand
{
get { return (ICommand)GetValue(MyCommandProperty); }
set { SetValue(MyCommandProperty, value); }
}
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register("MyCommand", typeof(ICommand), typeof(MyUserControlView),
new PropertyMetadata(null, MyCommandPropertyChangedCallback));
private static void MyCommandPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (MyUserControlView)d;
control.MyCommand = (DelegateCommand)e.NewValue;
}
void ExecuteMyCommand() {...}
bool CanExecuteMyCommand(){
return !string.IsNullOrWhiteSpace(MyProperty);
}
I Initialize this command with
SetValue(MyCommandProperty, new DelegateCommand(ExecuteMyCommand, CanExecuteMyCommand));
The problem is that the CanExecuteMyCommand() method does not work, because it does not use the current value of MyProperty. Why is this and how can I use my command correctly in a user control?
You have to invoke CanExecuteChanged after changing MyProperty it will call CanExecute.

Dependency Property to Dependency Property Binding

I want to bind two Dependency Property, both in one instance of object or different instance of object or different type of instance of object.
So, i read the docs:
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/how-to-create-a-binding-in-code?view=netframeworkdesktop-4.8
But i see the method is:
Set source:
set Path string which is a name of instance property with user defined type
set that source instance of object which contain that property which have that name
Set destination:
set destination instance of destination dependency property
set real static dependency property
So, my question is: Is exists any method to set two Dependency Property bind look like this:
SetBindingMethod(sourceInstanceOfObject, sourceDependencyProperty, destinationInstanceOfObject, destinationDependencyProperty)
Here is my test code is working, but not that what i want:
class TestClass : DependencyObject
{
public int Int0
{
get { return (int)GetValue(Int0Property); }
set { SetValue(Int0Property, value); }
}
public int Int1
{
get { return (int)GetValue(Int1Property); }
set { SetValue(Int1Property, value); }
}
public static readonly DependencyProperty Int0Property =
DependencyProperty.Register(nameof(Int0), typeof(int), typeof(TestClass), new PropertyMetadata(0, new PropertyChangedCallback(Int0Changed)));
public static readonly DependencyProperty Int1Property =
DependencyProperty.Register(nameof(Int1), typeof(int), typeof(TestClass), new PropertyMetadata(0, new PropertyChangedCallback(Int1Changed)));
private static void Int0Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine("Int0 changed: " + e.NewValue);
}
private static void Int1Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine("Int1 changed: " + e.NewValue);
}
internal void Test()
{
while(true)
{
Thread.Sleep(500);
Int0 += 1;
Thread.Sleep(500);
Int1 -= 1;
}
}
public TestClass()
{
Binding binding = new Binding(nameof(Int0));
binding.Source = this;
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(this, Int1Property, binding);
}
}
I hope that is clear, i'm on my limit of my english features :)
br: ExtSol

Data binding attached property to view model fails

I created an attached property for ListBox like this:
using ListBoxControl = System.Windows.Controls.ListBox;
namespace App.Ui.Views.AttachedProperties
{
public class ListBox
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxControl),
new PropertyMetadata(false));
public static void SetAutoScroll(ListBoxControl element, bool value)
{
element.SetValue(autoScrollProperty, value);
if (value)
{
element.SelectionChanged += Element_SelectionChanged;
}
else
{
element.SelectionChanged -= Element_SelectionChanged;
}
}
public static bool GetAutoScroll(ListBoxControl element)
{
return (bool)element.GetValue(autoScrollProperty);
}
private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBoxControl)sender;
listBox.ScrollIntoView(listBox.SelectedItem);
}
}
}
When I use a static True/False value in the xaml, it works fine:
<ListBox ap:ListBox.AutoScroll="True">
...
</ListBox>
But if I data bind to a property in my view model:
<ListBox ap:ListBox.AutoScroll="{Binding Path=Settings.EnableAutoScroll}">
...
</ListBox>
Then I get the following exception: A 'Binding' cannot be set on the 'SetAutoScroll' property of type 'ListBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Is this possible, or am I going to need to derive my own custom list box to accomplish this?
Problem in this line typeof(ListBoxControl). You should specify the name of the class where custom attached property seats.
I would recommend rename class from ListBox to ListBoxExtensions, also, make it static. Then you don't have to use alias ListBoxControl.
Your final code will look like:
public static class ListBoxExtensions
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxExtensions),
new PropertyMetadata(false));
...
}
Edit:
OK, your code has another problem.
Remove attachment of the listener from setter (SetAutoScroll) and put this logic into dependency property callback.
public static class ListBoxExtensions
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxExtensions),
new PropertyMetadata(false, AutoScrollChangedCallback));
public static void SetAutoScroll(ListBox element, bool value)
{
element.SetValue(autoScrollProperty, value);
}
public static bool GetAutoScroll(ListBox element)
{
return (bool)element.GetValue(autoScrollProperty);
}
private static void AutoScrollChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBox control = (ListBox)d;
if ((bool)e.NewValue)
{
control.SelectionChanged += Element_SelectionChanged;
}
else
{
control.SelectionChanged -= Element_SelectionChanged;
}
}
private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBox)sender;
listBox.ScrollIntoView(listBox.SelectedItem);
}
}

C# WPF Binding value does not trigger animation to in user control

Hello I have issue with binding to user control animation, after I bind data to user control(which is bool type) it sets correct values to user control data, but does not trigger animation, I tried to use PropertyChangedCallback but with no luck user control code below:
private static Switch_box AppWindow;
public Switch_box()
{
InitializeComponent();
AppWindow = this;
}
public static readonly DependencyProperty CheckboxStatusProperty = DependencyProperty.Register(nameof(CheckboxStatus), typeof(bool), typeof(Switch_box), new PropertyMetadata(false, new PropertyChangedCallback(OnCurrentReadingChanged)));//cant remove static otherwise throws error
public bool CheckboxStatus
{
get
{
return (bool)GetValue(CheckboxStatusProperty);
}
set
{
/* if (value == true)
{
((Storyboard)FindResource("OnChecking")).Begin(this);
}
else
{
((Storyboard)FindResource("OnUnchecking")).Begin(this);
}*/
SetValue(CheckboxStatusProperty, value);
}
}
private static void OnCurrentReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)//cant remove static due to PropertyChangedCallBack requires static otherwise it throws error
{
AppWindow.OnChecking((bool)d.GetValue(CheckboxStatusProperty));
}
private void OnChecking(bool Status)
{
switch (Status)
{
case true:
{
((Storyboard)FindResource("OnChecking")).Begin(this);
break;
}
case false:
{
((Storyboard)FindResource("OnUnchecking")).Begin(this);
break;
}
}
}
And my usercontrol bind line:
<local:Switch_box Tag="{Binding Index,IsAsync=True}" Checked="Switch_box_Checked" Unchecked="Switch_box_Unchecked" CheckboxStatus="{Binding IsEnabled,IsAsync=True}"/>
How to trigger animation after CheckboxStatus variable is changed?
EDIT 1: updated code.
There is a naming convention. _StatusBox should be named CheckboxStatusProperty, and it should be public:
public static readonly DependencyProperty CheckboxStatusProperty =
DependencyProperty.Register(
nameof(CheckboxStatus), typeof(bool), typeof(Switch_box),
new PropertyMetadata(false, OnCurrentReadingChanged));
You must not call anything else than GetValueand SetValue in the CLR wrapper of a dependency property. And you call the methods on the current instance, not on a static field:
public bool CheckboxStatus
{
get { return (bool)GetValue(CheckboxStatusProperty); }
set { SetValue(CheckboxStatusProperty , value); }
}
In the PropertyChangedCallback it is pointless to set the property another time. And again, you should operate on the current DependencyObject instance, i.e. d, not on a static field:
private static void OnCurrentReadingChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Switch_box)d).OnChecking((bool)e.NewValue);
}
private void OnChecking(bool status)
{
if (status)
{
((Storyboard)FindResource("OnChecking")).Begin(this);
}
else
{
((Storyboard)FindResource("OnUnchecking")).Begin(this);
}
}

Loaded event and data-binding in WPF

Suppose we have a control with a dependency property:
public class MyControl : ContentControl
{
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
}
void DoSomething(object sender, RoutedEventArgs e)
{
//...
}
public MyControl()
{
this.Loaded += DoSomething;
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(string), typeof(MyControl),
new FrameworkPropertyMetadata(default(string),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//some actions
}
public string Value
{
get { return (string)GetValue(MyControl.ValueProperty); }
set { SetValue(MyControl.ValueProperty, value); }
}}
And somewhere in XAML we bind ValueProperty to some property Val of some ViewModel.
My question is, at the moment when Loaded event is fired, will the value of MyControl.Value be already set to the value of Val which it has or not? So, am I able to use Val in DoSomething method which is executed when MyControl is loaded or not?
Thank you in advance for any answers.
My question is, at the moment when Loaded event is fired, will the value of MyControl.Value be already set to the value of Val which it has or not?
You cannot rely on this. The Loaded event is not a 'data-binding-has-completed' event. Also, the value of a dependency property can change at any time and the place to handle any changes to your Value property is in the OnValueChanged callback. You could check whether the control has been loaded in the callback if you want to:
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl ctrl = d as MyControl;
if (ctrl.IsLoaded)
{
//...
}
}
The point is that you should perform any action that depends upon the value of your dependency property in the callback and not in the Loaded event handler.
public class MyControl : ContentControl
{
public MyControl()
{
this.Loaded += (s,e) => DoSomething();
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (MyControl)d;
if ( c.IsLoaded )
c.DoSomething();
}
// this will be called only if the control is loaded
private void DoSomething()
{
var value = Value;
if ( value == null )
{
...
} else if ( value == string.Empty )
{
...
} else
{
}
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(string), typeof(MyControl),
new FrameworkPropertyMetadata(default(string),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, OnValueChanged));
public string Value
{
get { return (string)GetValue(MyControl.ValueProperty); }
set { SetValue(MyControl.ValueProperty, value); }
}
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
}
}

Categories

Resources