I wish to use attached properties in my application by making use of the code below (and taken from here). However, Intellisense in Visual Studio will not show the registered Attached Properties for some reason unknown to me. My application is an add-in and constrained to be a class library (.Net Framework 4.7.2)
Viewing the code below and taking cognizance of the definition for Attached Properties, I would think that the attached property would be defined as such
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value",
typeof(Property),
**typeof(Parent)**,
new UIPropertyMetadata(
default(Property),
new PropertyChangedCallback(OnValuePropertyChanged),
new CoerceValueCallback(OnValuePropertyUpdated)
));
and NOT as such
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value",
typeof(Property),
**typeof(BaseAttachedProperty<Parent, Property>)**,
new UIPropertyMetadata(
default(Property),
new PropertyChangedCallback(OnValuePropertyChanged),
new CoerceValueCallback(OnValuePropertyUpdated)
));
Notice the difference between typeof(Parent) and typeof(BaseAttachedProperty<Parent, Property>). However, when I use this code in a Visual Studio Class Library, Intellisense does not show the defined Attached Properties that are defined for example:
public class IsBusyProperty : BaseAttachedProperty<IsBusyProperty, bool>
{
}
Intellisense shows the cryptic information: local:BaseAttachedProperty`2.Value which I understand refers to the Base Class with two parameters. Is there some particular method to handle Generics and Base Classes with WPF so that Attached Properties are recognized as being in this Namespace and also being consumable? My goal is to ease the creation and consumption of Attached Properties in my application. I have done the cleaning, deletion of the bin folder to no avail. However, when I write an own AP for example:
public class IsBusyProperty
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.RegisterAttached("Value", typeof(bool), typeof(IsBusyProperty), new PropertyMetadata(false));
public static bool GetValue(DependencyObject obj)
{
return (bool)obj.GetValue(ValueProperty);
}
public static void SetValue(DependencyObject obj, bool value)
{
obj.SetValue(ValueProperty, value);
}
}
the code compiles without the dreaded error that the attached property is not found in the namespace local:... or the No implementation exception!
Here is the reference code taken from here.
using System;
using System.ComponentModel;
using System.Windows;
namespace Fasetto.Word
{
/// <summary>
/// A base attached property to replace the vanilla WPF attached property
/// </summary>
/// <typeparam name="Parent">The parent class to be the attached property</typeparam>
/// <typeparam name="Property">The type of this attached property</typeparam>
public abstract class BaseAttachedProperty<Parent, Property>
where Parent : new()
{
#region Public Events
/// <summary>
/// Fired when the value changes
/// </summary>
public event Action<DependencyObject, DependencyPropertyChangedEventArgs> ValueChanged = (sender, e) => { };
/// <summary>
/// Fired when the value changes, even when the value is the same
/// </summary>
public event Action<DependencyObject, object> ValueUpdated = (sender, value) => { };
#endregion
#region Public Properties
/// <summary>
/// A singleton instance of our parent class
/// </summary>
public static Parent Instance { get; private set; } = new Parent();
#endregion
#region Attached Property Definitions
/// <summary>
/// The attached property for this class
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value",
typeof(Property),
typeof(BaseAttachedProperty<Parent, Property>),
new UIPropertyMetadata(
default(Property),
new PropertyChangedCallback(OnValuePropertyChanged),
new CoerceValueCallback(OnValuePropertyUpdated)
));
/// <summary>
/// The callback event when the <see cref="ValueProperty"/> is changed
/// </summary>
/// <param name="d">The UI element that had it's property changed</param>
/// <param name="e">The arguments for the event</param>
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Call the parent function
(Instance as BaseAttachedProperty<Parent, Property>)?.OnValueChanged(d, e);
// Call event listeners
(Instance as BaseAttachedProperty<Parent, Property>)?.ValueChanged(d, e);
}
/// <summary>
/// The callback event when the <see cref="ValueProperty"/> is changed, even if it is the same value
/// </summary>
/// <param name="d">The UI element that had it's property changed</param>
/// <param name="e">The arguments for the event</param>
private static object OnValuePropertyUpdated(DependencyObject d, object value)
{
// Call the parent function
(Instance as BaseAttachedProperty<Parent, Property>)?.OnValueUpdated(d, value);
// Call event listeners
(Instance as BaseAttachedProperty<Parent, Property>)?.ValueUpdated(d, value);
// Return the value
return value;
}
/// <summary>
/// Gets the attached property
/// </summary>
/// <param name="d">The element to get the property from</param>
/// <returns></returns>
public static Property GetValue(DependencyObject d) => (Property)d.GetValue(ValueProperty);
/// <summary>
/// Sets the attached property
/// </summary>
/// <param name="d">The element to get the property from</param>
/// <param name="value">The value to set the property to</param>
public static void SetValue(DependencyObject d, Property value) => d.SetValue(ValueProperty, value);
#endregion
#region Event Methods
/// <summary>
/// The method that is called when any attached property of this type is changed
/// </summary>
/// <param name="sender">The UI element that this property was changed for</param>
/// <param name="e">The arguments for this event</param>
public virtual void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { }
/// <summary>
/// The method that is called when any attached property of this type is changed, even if the value is the same
/// </summary>
/// <param name="sender">The UI element that this property was changed for</param>
/// <param name="e">The arguments for this event</param>
public virtual void OnValueUpdated(DependencyObject sender, object value) { }
#endregion
}
}
Related
If the property event will trigger I want a method that will be called
For example. If the name of person is changed the MethodOne() will be also called. How to implement this with INotifyPropertyChanged on another class for example on WPF MainWindow.xaml.cs? Thank You
public class ObservableObject : INotifyPropertyChanged
{
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler? PropertyChanged;
}
...
There a few ways that you can get notified of property changed.
Generally you should always define properties using DependencyProperty.Register and then add access methods.
In the example that follows change YourClass to be your class name.
Declare the property like this, note that the new PropertyMetadata specifies a static method to call when the property is changed. This can be useful but is optional and can be omitted.
/// <summary>
/// Backs the IsBusy dependency property.
/// </summary>
public static readonly DependencyProperty IsBusyProperty =
DependencyProperty.Register(
"IsBusy",
typeof( bool ),
typeof( YourClass ),
new PropertyMetadata( false, new PropertyChangedCallback( OnIsBusyChanged ) ) );
then provide an access method that will use the underlying backing property, so that any changes can be tracked.
/// <summary>
/// Gets or sets a value indicating whether the busy indicator should show.
/// </summary>
public bool IsBusy
{
get
{
return ( bool )GetValue( IsBusyProperty );
}
set
{
SetValue( IsBusyProperty, value );
}
}
The following is the static interface to the dependency property that is required to be static. In here we will receive the dependency object that will usually be an instance of your class and thus we can invoke an object method from that class.
/// <summary>
/// IsBusyProperty property changed handler.
/// </summary>
/// <remarks>
/// This is the static version that is invoked by the dependency property
/// with the appropriate object, so see if d is our class and if so then
/// we can invoke the method on the class
/// </remarks>
/// <param name="d">Instance of class that changed its IsBusy.</param>
/// <param name="e">Event arguments.</param>
private static void OnIsBusyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
if (d is YourClass)
{
var bb = d as YourClass;
bb.OnIsBusyChanged(e);
}
}
and finally the method that will be called when the property is changed in the object
/// <summary>
/// IsBusyProperty property changed handler.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnIsBusyChanged(DependencyPropertyChangedEventArgs e)
{
// your code
// you could notify a parent or another event
// handler
}
As an alternative you can directly attach to the PropertyChanged event.
In your constructor (or somewhere)
PropertyChanged += somePropertyChanged;
this will then call the method somePropertyChanged which is defined as follows:
private void somePropertyChanged(object sender, PropertyChangedEventArgs e)
{
// sender is the object that caused the change
// and is usually your class
Console.WriteLine("Property {0} changed", e.PropertyName);
}
The first approach of specifying a callback in DependencyProperty.Register can be useful when you have a set of properties that can be considered as a group and when a similar action will be taken.
I'm newer to coding, as a warning not an excuse. I currently have a quick timer class 'wrapper' I use. While most of the time I've used it, it worked as expected, I now have an issue.
The code the timer calls back does not always have a set or even accurate estimate of how long it will take to execute that chunk of code start to finish. This leaves me with abnormally long timer update intervals to account for it, or, alternatively stop the timer, and start it again each time it 'ticks' to prevent over-lap.
I've found the first method unacceptable in my case. The second one sounded perfect, but when I tried it it slowed down the code a lot and could have easily ticked much more often after I reviewed it. I'm not sure why it slows it down so much.
Should I look at another way at doing this, besides timers, like some kind of manual control over the flow of events? This is for a simple game-update loop class. Here is said class in full below.
public class TimedUpdater<T>
{
#region Public Delegates/Events
/// <summary>
/// An event that is raised repeatedly at the Interval[in milliseconds] for this Instance.
/// </summary>
public event EventHandler<T> OnUpdate;
#endregion
#region Fields, Private Properties
private Timer Timer { get; }
private TimerCallback Callback { get; }
private T State { get; }
#endregion
#region Constructors, Destructors
/// <summary>
/// Initializes a new instance of the <see cref="TimedUpdater{T}" /> class.
/// </summary>
/// <param name="state">The state object to use for updating data.</param>
/// <param name="name">The unique name representing this instance.</param>
/// <param name="updateRateMs">The rate the the <code>OnUpdate</code> event is raised in milliseconds.</param>
public TimedUpdater(T state, string name, int updateRateMs)
{
Name = name;
Interval = updateRateMs;
State = state;
Callback += Process;
Timer = new Timer(Callback, State, Timeout.Infinite, Timeout.Infinite);
}
/// <summary>
/// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage
/// collection.
/// </summary>
~TimedUpdater()
{
Dispose();
}
#endregion
#region Public Properties, Indexers
/// <summary>
/// Gets or sets the interval in milliseconds.
/// </summary>
/// <value>The interval in milaseconds.</value>
public int Interval { get; set; }
/// <summary>
/// States if the updater is enabled.
/// </summary>
public bool IsEnabled { get; private set; }
/// <summary>
/// Gets the unique name that represents this instance.
/// </summary>
/// <value>The name.</value>
public string Name { get; }
#endregion
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Disable();
Timer.Dispose();
}
/// <summary>
/// Enables the updater.
/// </summary>
public void Enable()
{
Timer.Change(Interval, Interval);
IsEnabled = true;
}
/// <summary>
/// Disables the updater.
/// </summary>
public void Disable()
{
Timer.Change(int.MaxValue, Interval);
IsEnabled = false;
}
/// <summary>
/// Processes the specified object casted to the type.
/// </summary>
/// <param name="e">The e.</param>
protected virtual void Process(object e)
{
OnUpdate?.Invoke(this, (T) e);
}
}
I have created a new user control. I would like to listen for when the Visibility property has changed so that I can do some extra work at the same time. I know that it is a dependency property, but it isn't one I created, so I am struggling to understand how to hook into it. In WinRT apps, there is not OverrideMetadata method, which seems to be the most common way to do this. I also tried creating a new dependency property that registered to the existing property name, but that callback was never fired.
I have to believe that there is some way for a dependency object to listen for it's own property changes. What am I missing?
I have used something like this in my user control. You can then subscribe to the VisibilityChanged event. Note that I am using the new keyword on the property.
/// <summary>
/// The current visiblity of this user control.
/// </summary>
private Visibility _visibility;
/// <summary>
/// Gets or sets the visibility of a UIElement.
/// A UIElement that is not visible is not rendered and does not communicate its desired size to layout.
/// </summary>
/// <returns>A value of the enumeration. The default value is Visible.</returns>
public new Visibility Visibility
{
get { return _visibility; }
set
{
bool differ = false;
if (value != _visibility)
{
_visibility = value;
differ = true;
}
base.Visibility = value;
if (differ)
{
RaiseVisibilityChanged(value);
}
}
}
/// <summary>
/// Raised when the <see cref="Visibility"/> property changes.
/// </summary>
public event EventHandler<VisibilityChangedEventArgs> VisibilityChanged;
/// <summary>
/// Raises the <see cref="VisibilityChanged"/> event of this command bar.
/// </summary>
/// <param name="visibility">The new visibility value.</param>
private void RaiseVisibilityChanged(Visibility visibility)
{
if (VisibilityChanged != null)
{
VisibilityChanged(this, new VisibilityChangedEventArgs(visibility));
}
}
/// <summary>
/// Contains the arguments for the <see cref="SampleViewModel.VisibilityChanged"/> event.
/// </summary>
public sealed class VisibilityChangedEventArgs : EventArgs
{
/// <summary>
/// The new visibility.
/// </summary>
public Visibility NewVisibility { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="VisibilityChangedEventArgs"/> class.
/// <param name="newVisibility">The new visibility.</param>
/// </summary>
public VisibilityChangedEventArgs(Visibility newVisibility)
{
this.NewVisibility = newVisibility;
}
}
I'm trying to bind a datagrid (WPF C# 4.0 with WPF Toolkit) to the fields of a structure. I basically have a datagrid with two columns. The first I would like to be labels, the second I would like to be the members of a structure. Perferably I would like to treat the series of rows as a single structure which can then be used elsewhere in my program.
Currently I have the program adding new instances of some class for each row, but I would prefer to treat it all as one... is there a way?
Thanks
ViewModel
/// <summary>
/// DataGridRowViewModel
/// </summary>
public class DataGridRowViewModel:BaseViewModel
{
/// <summary>
/// structureField
/// </summary>
private string structureField;
private string lableText;
/// <summary>
/// StructureField
/// </summary>
public string StructureField
{
get { return structureField; }
set
{
structureField= value;
OnPropertyChanged("StructureField");
}
}
/// <summary>
/// StructureField
/// </summary>
public string LableText
{
get { return lableText; }
set
{
lableText= value;
OnPropertyChanged("LableText");
}
}
}
/// <summary>
/// DataGridRowViewModel
/// </summary>
public class MainViewModel:BaseViewModel
{
/// <summary>
/// structureField
/// </summary>
private ObservableCollection<DataGridRowViewModel> rowCollection;
//Make Property with INotifyPropertyChanged
/// <summary>
/// Default Constructor
/// </summary>
public MainViewModel()
{
RowCollection = new ObservableCollection<DataGridRowViewModel>();
FillCollectionWithStructureFields();
}
private void FillCollectionWithStructureFields()
{
//Fill Add New Instances of DataGridRowViewModel with required Label
// and Structure Filead Values
}
}
View
Bind the collection to DataGrid with required Columns...
I was handling yet another KeyDown event in a user control when I wondered if it existed a library for typing fluent code for handling event like
editor.When(Keys.F).IsDown().With(Keys.Control).Do((sender, e) => ShowFindWindow());
Does that exist?
I decided that this was a challenge and that this could let me learn what Fluent is, so I coded a Fluent keyboard class. I don't think I follow all fluent language structure and rules, but it work.
Helper extension method
/// <summary>
/// Provides a set of static (Shared in Visual Basic) methods for starting a fluent expression on a <see cref="System.Windows.Form.Control"/> object.
/// </summary>
public static class ControlExtensions
{
/// <summary>
/// Starts a fluent expression that occurs when a key is pressed.
/// </summary>
/// <param name="control">The control on which the fluent keyboard expression is occuring.</param>
/// <param name="keys">The key when it will happen.</param>
/// <returns>A <see cref="KeyboardFluent"/> object that makes it possible to write a fluent expression.</returns>
public static KeyboardFluent When(this Control control, Keys keys)
{
return new KeyboardFluent(control).When(keys);
}
}
The fluent class
/// <summary>
/// Represents a fluent expression for handling keyboard event.
/// </summary>
public class KeyboardFluent
{
/// <summary>
/// The control on which the fluent keyboard expression is occuring.
/// </summary>
private Control control;
/// <summary>
/// The KeyDown and KeyUp handler.
/// </summary>
private KeyEventHandler keyHandler;
/// <summary>
/// Stores if the IsDown method was called and that the KeyDown event is registered.
/// </summary>
private bool isDownRegistered = false;
/// <summary>
/// Stores if the IsUp method was called and that the KeyUp event is registered.
/// </summary>
private bool isUpRegistered = false;
/// <summary>
/// The list of keys that will make the actions be executed when they are down or up.
/// </summary>
private List<Keys> triggerKeys;
/// <summary>
/// The modifiers keys that must be down at the same time than the trigger keys for the actions to be executed.
/// </summary>
private Keys modifiers;
/// <summary>
/// The list of actions that will be executed when the trigger keys and modifiers are down or up.
/// </summary>
private List<Action<object, KeyEventArgs>> actions;
/// <summary>
/// Initializes a new instance of the <see cref="KeyboardFluent"/> class.
/// </summary>
/// <param name="control">The control on which the fluent keyboard expression is occuring.</param>
public KeyboardFluent(Control control)
{
this.control = control;
this.triggerKeys = new List<Keys>();
this.actions = new List<Action<object, KeyEventArgs>>();
this.keyHandler = new KeyEventHandler(OnKeyHandler);
}
/// <summary>
/// Handles the KeyDown or KeyUp event on the control.
/// </summary>
/// <param name="sender">The control on which the event is occuring.</param>
/// <param name="e">A <see cref="KeyEventArgs"/> that gives information about the keyboard event.</param>
private void OnKeyHandler(object sender, KeyEventArgs e)
{
if (this.triggerKeys.Contains(e.KeyCode) && e.Modifiers == this.modifiers)
{
this.actions.ForEach(action => action(sender, e));
}
}
/// <summary>
/// Makes the keyboard event occured when a key is pressed down.
/// </summary>
/// <returns>Returns itself to allow a fluent expression structure.</returns>
public KeyboardFluent IsDown()
{
if (!isDownRegistered)
{
this.control.KeyDown += this.keyHandler;
isDownRegistered = true;
}
return this;
}
/// <summary>
/// Makes the keyboard event occured when a key is pressed up.
/// </summary>
/// <returns>Returns itself to allow a fluent expression structure.</returns>
public KeyboardFluent IsUp()
{
if (!isUpRegistered)
{
this.control.KeyUp += this.keyHandler;
isUpRegistered = true;
}
return this;
}
/// <summary>
/// Creates a new trigger on a key.
/// </summary>
/// <param name="key">The key on which the actions will occur.</param>
/// <returns>Returns itself to allow a fluent expression structure.</returns>
public KeyboardFluent When(Keys key)
{
this.triggerKeys.Add(key);
return this;
}
/// <summary>
/// Adds a modifier filter that is checked before the action are executed.
/// </summary>
/// <param name="modifiers">The modifier key.</param>
/// <returns>Returns itself to allow a fluent expression structure.</returns>
public KeyboardFluent With(Keys modifiers)
{
this.modifiers |= modifiers;
return this;
}
/// <summary>
/// Executes the action when the specified keys and modified are either pressed down or up.
/// </summary>
/// <param name="action">The action to be executed.</param>
/// <returns>Returns itself to allow a fluent expression structure.</returns>
public KeyboardFluent Do(Action<object, KeyEventArgs> action)
{
this.actions.Add(action);
return this;
}
}
I can now type
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.When(Keys.F).With(Keys.Control).IsDown().Do((sender, e) => MessageBox.Show(e.KeyData.ToString()));
}
}
and it will display the messagebox only when Ctrl+F is down.
I downloaded the Reactive Extension Framework for the .Net Framework 3.5 SP1.
I was able to do the same:
Observable.FromEvent<KeyEventArgs>(this, "KeyDown")
.Where(e => e.EventArgs.KeyCode == Keys.F && e.EventArgs.Modifiers == Keys.Control)
.Subscribe(e => MessageBox.Show(e.EventArgs.KeyData.ToString()));
This is some pretty powerful stuff.
.NET 4 will introduce the reactive framework (IObservable<T>, IObserver<T> and helper extension types) which should offer exactly this.