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

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);
}
}

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.

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);
}
}

How to update one dependency property from another in UWP

I have two dependency properties and when value in First changes, I would like to update also the Second - for example give it temporary value and update UI, but I don't want to break the binding on Second property.
public bool Frist
{
get { return (bool)GetValue(FristProperty); }
set { SetValue(FristProperty, value); }
}
public static readonly DependencyProperty FristProperty =
DependencyProperty.Register("Frist", typeof(bool), typeof(ItemControl), new PropertyMetadata(false, FirstUpdated));
private static void FirstUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var theControl = d as ItemsControl;
// I would like to update also second dependency property here
// for example if First == true, then Second = Overriden
// else Second = the value from binding
}
public string Second
{
get { return (string)GetValue(SecondProperty); }
set { SetValue(SecondProperty, value); }
}
public static readonly DependencyProperty SecondProperty =
DependencyProperty.Register("Second", typeof(string), typeof(ItemsControl), new PropertyMetadata(string.Empty));
I've taken a look at various samples from WPF, but seems like there are missing things in UWP. What are the options?

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)));
}
}

DependencyProperty of Custom Type won't fire propertychanged callback

Premise: I read all the others threads about similar issues but none of those solved my problem.
I have a UserControl (SummarySource) with 3 DP:
public static DependencyProperty QueryProperty;
public static DependencyProperty MaxRowsPerPageProperty;
public static DependencyProperty OpcSessionProperty;
And the respective public getters and setters:
[Category("Common")]
public String Query
{
get { return (String)GetValue(QueryProperty); }
set { SetValue(QueryProperty, value); }
}
[Category("Common")]
public UInt32 MaxRowsPerPage
{
get { return (UInt32)GetValue(MaxRowsPerPageProperty); }
set { SetValue(MaxRowsPerPageProperty, value); }
}
[Category("Common")]
public UaSession OpcSession
{
get { return (UaSession)GetValue(OpcSessionProperty); }
set { SetValue(OpcSessionProperty, value); }
}
The problem is that tha PropertyChanged Callback for the "OpcSession" variable (the only one that is a custom type) isn't fired.
Static Constructor
OpcSessionProperty = DependencyProperty.Register("OpcSession", typeof(UaSession), typeof(SummarySource), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnSessionChanged)));
The Callback
private static void OnSessionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("He3e1");
SummarySource thisControl = (SummarySource)sender;
if (thisControl.DataContext != null)
{
((DataRetriever)thisControl.DataContext).SetOpcSession((UaSession)e.NewValue);
}
}
The MessageBox is never showed. If I put a MessageBox.Show on the other callbacks I can see the message when Load the form that use the control or change the value in xaml.
The .Xaml
<Window.DataContext>
<cs:UaSession x:Name="opcSession" EndpointUrl="opc.tcp://192.168.200.11:62543/Runtime"/>
</Window.DataContext>
<control:SummarySource x:Key="qq" MaxRowsPerPage="25" OpcSession="{Binding Path=DataContext, ElementName=window, PresentationTraceSources.TraceLevel=High, Mode=TwoWay}" />
No Binding Errors in output

Categories

Resources