Using Dependency Property's to Affect Non WPF Property's
-
Im building a Ticker User Control and my dependency property's that directly bind to the XAML which works great, but I have some dependency property's that drive the Beating Internal Class which controls the motion of the three bars. When I change these in the viewmodel they have no affect on the Internal Class Property's so I cant change the speed or starting length and so on. I though if I passed in the Code behind class into the Beating internal class I could do it this way, but i almost need an onPropertychanged event to force the update. thanks Madaxe XAML User Control
-
Im building a Ticker User Control and my dependency property's that directly bind to the XAML which works great, but I have some dependency property's that drive the Beating Internal Class which controls the motion of the three bars. When I change these in the viewmodel they have no affect on the Internal Class Property's so I cant change the speed or starting length and so on. I though if I passed in the Code behind class into the Beating internal class I could do it this way, but i almost need an onPropertychanged event to force the update. thanks Madaxe XAML User Control
Marc Jeeves wrote:
public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
A
DependencyObject
such as aUserControl
doesn't need to implementINotifyPropertyChanged
. TheDependencyProperty
already raises the necessary events when the value changes. You're passing in the current value of aDependencyProperty
to theBeating
class. At that point, there is no connection between theint
in theBeating
class and theDependencyProperty
. The simplest option is probably to reverse the connection, and use binding to move the values around when they change:internal sealed class Beating : INotifyPropertyChanged
{
private readonly Timer? _timer;
private int _value;
private bool _direction;public int Value { get { return \_value; } set { if (value != \_value) { \_value = value; OnPropertyChanged(); } } } public int Increment { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public string BeatName { get; } public double Speed { get { return \_timer.Interval; } set { \_timer.Interval = value; } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(\[CallerMemberName\] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public Beating(int initialValue, int increment, int minValue, int maxValue, string beatName, double speed) { \_value = initialValue; Increment = increment; MinValue = minValue; MaxValue = maxValue; BeatName = beatName; \_timer = new Timer { Interval = speed, AutoReset = true, Enabled = true, }; \_timer.Elapsed += OnTimedEvent; } public void StartTimer() { \_timer.Start(); } public void StopTimer() { \_timer.Stop(); } private void OnTimedEvent(Object source, ElapsedEventArgs e) { if (!\_direction) { Value -= Increment; if (Value < MinValue) \_direction
-
Marc Jeeves wrote:
public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
A
DependencyObject
such as aUserControl
doesn't need to implementINotifyPropertyChanged
. TheDependencyProperty
already raises the necessary events when the value changes. You're passing in the current value of aDependencyProperty
to theBeating
class. At that point, there is no connection between theint
in theBeating
class and theDependencyProperty
. The simplest option is probably to reverse the connection, and use binding to move the values around when they change:internal sealed class Beating : INotifyPropertyChanged
{
private readonly Timer? _timer;
private int _value;
private bool _direction;public int Value { get { return \_value; } set { if (value != \_value) { \_value = value; OnPropertyChanged(); } } } public int Increment { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public string BeatName { get; } public double Speed { get { return \_timer.Interval; } set { \_timer.Interval = value; } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(\[CallerMemberName\] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public Beating(int initialValue, int increment, int minValue, int maxValue, string beatName, double speed) { \_value = initialValue; Increment = increment; MinValue = minValue; MaxValue = maxValue; BeatName = beatName; \_timer = new Timer { Interval = speed, AutoReset = true, Enabled = true, }; \_timer.Elapsed += OnTimedEvent; } public void StartTimer() { \_timer.Start(); } public void StopTimer() { \_timer.Stop(); } private void OnTimedEvent(Object source, ElapsedEventArgs e) { if (!\_direction) { Value -= Increment; if (Value < MinValue) \_direction
Thanks I will give it a try, and post the full example once completed for others.
-
Marc Jeeves wrote:
public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
A
DependencyObject
such as aUserControl
doesn't need to implementINotifyPropertyChanged
. TheDependencyProperty
already raises the necessary events when the value changes. You're passing in the current value of aDependencyProperty
to theBeating
class. At that point, there is no connection between theint
in theBeating
class and theDependencyProperty
. The simplest option is probably to reverse the connection, and use binding to move the values around when they change:internal sealed class Beating : INotifyPropertyChanged
{
private readonly Timer? _timer;
private int _value;
private bool _direction;public int Value { get { return \_value; } set { if (value != \_value) { \_value = value; OnPropertyChanged(); } } } public int Increment { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } public string BeatName { get; } public double Speed { get { return \_timer.Interval; } set { \_timer.Interval = value; } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(\[CallerMemberName\] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public Beating(int initialValue, int increment, int minValue, int maxValue, string beatName, double speed) { \_value = initialValue; Increment = increment; MinValue = minValue; MaxValue = maxValue; BeatName = beatName; \_timer = new Timer { Interval = speed, AutoReset = true, Enabled = true, }; \_timer.Elapsed += OnTimedEvent; } public void StartTimer() { \_timer.Start(); } public void StopTimer() { \_timer.Stop(); } private void OnTimedEvent(Object source, ElapsedEventArgs e) { if (!\_direction) { Value -= Increment; if (Value < MinValue) \_direction
So I have three last issues, thanks for all the help 1) if I use the usercontrol name "Name="WaitTickerCustomControl" then the Custom Control disappears in the Main Window odd. 2) The directly Bound dependency property are bound but nothing updates 3) The Indirectly Bound property's only affect the third ticker odd... Thanks for the help im learning alot. Madaxe XAML Custom Control
-
Thanks I will give it a try, and post the full example once completed for others.
-
So I have three last issues, thanks for all the help 1) if I use the usercontrol name "Name="WaitTickerCustomControl" then the Custom Control disappears in the Main Window odd. 2) The directly Bound dependency property are bound but nothing updates 3) The Indirectly Bound property's only affect the third ticker odd... Thanks for the help im learning alot. Madaxe XAML Custom Control
ElementName=WaitTickerCustomControl
A pointless assignment. Which is addressed by a simple
this.DataContext = this;
in the constructor. (Which may be required in any case). All your "dependency properties", on first glance, look like a reach that could have been defaulted in code behind; complimented with an "options" flyout / popup.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
-
ElementName=WaitTickerCustomControl
A pointless assignment. Which is addressed by a simple
this.DataContext = this;
in the constructor. (Which may be required in any case). All your "dependency properties", on first glance, look like a reach that could have been defaulted in code behind; complimented with an "options" flyout / popup.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
Gerry Schmitz wrote:
this.DataContext = this;
Which will almost certainly bring you back to the original problem[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Gerry Schmitz wrote:
this.DataContext = this;
Which will almost certainly bring you back to the original problem[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Each control has a DataContext. You can let them default to a "higher up", or set them each explicitly. Setting a DataContext is rarely an issue; omitting them is. The excess of pointless XAML and dependency properties is obfuscating the problem. That was my (indirect) point.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
-
Each control has a DataContext. You can let them default to a "higher up", or set them each explicitly. Setting a DataContext is rarely an issue; omitting them is. The excess of pointless XAML and dependency properties is obfuscating the problem. That was my (indirect) point.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
So how would you guys build this custom control?
-
So how would you guys build this custom control?
You're actually creating a user control; and not a "custom control". The "simplest" way to create a user control is to add properties {get;set;} to the UC in the .cs; bind the controls in the .xaml to the properties in the .cs; and implement INotifyPropertyChanged (which for a "few" controls, can be issued with "no contol name" without any hit on performance). The DataContext of the UC is the UC; i.e. "this". Any time there is new data, you load the properties and call "property changed" which updates the UI. If it's a two-way UI, data moves to the properties and events on the controls get invoked (e.g. text changed). That's the pattern, and most everything else has a "smell". X| :-\ Anything else that happens is a function of what events the user control wants to "surface" (e.g. a request queued to an observable collection or file watcher).
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I