I have an abstract base class that subclasses the UserControl class with no XAML. When I create a class based on the base class everything works fine (compiles and executes). But when I add code to the base class to fire an event, it compiles but when run I get a 'The invocation of the constructor on type 'ExtendedDisplay.UserControls.Annotations' that matches the specified binding constraints threw an exception.' error. Not sure why.
Here is my code for the base class,
public abstract class BaseClass: UserControl
{
protected static System.Type ControlType;
public static readonly RoutedEvent RefreshEvent = EventManager.RegisterRoutedEvent(
"RefreshEvent",
RoutingStrategy.Bubble,
typeof(RefreshEventHandler),
ControlType);
public delegate void RefreshEventHandler(object sender, RefreshEventArgs e);
public event RefreshEventHandler RefreshNeeded
{
add { AddHandler(RefreshEvent, value); }
remove { RemoveHandler(RefreshEvent, value); }
}
protected void RaiseRefreshEvent(RoutedEventArgs e)
{
RaiseEvent(new RefreshEventArgs(RefreshEvent, this));
e.Handled = true;
}
public class RefreshEventArgs : RoutedEventArgs
{
public RefreshEventArgs(RoutedEvent routedEvent, object source)
: base(routedEvent, source) { }
}
}
This code works as expected when hardcoded into the UserControl. Any ideas/help would be greatly appreciated.
On further testing it appears that I can't replace the last parameter in the EventManager.RegisterRoutedEvent function with a variable. I have a variable "protected static System.Type ControlType;" that is set to the typeof control by the derived control. This doesn't work when hard coded either. To make it work, I can't use a variable, even though it is the right type. Is ther any way around this?
Ok,
Finally figured it out. What I did was to have the baseclass member "RefreshEvent" just declared in the baseclass and assigned in the derived class. This works great and does what I need keeping the bulk of the boilerplate in the baseclass.
Related
This won't go away now matter what i try, even though i have done everything according to the course i'm following.
'Inputreader' does not implement interface member 'Controls.IPlayerActions.OnDodge(InputAction.CallbackContext)'
Here is the code
public class Inputreader : MonoBehaviour, Controls.IPlayerActions
{
private Controls controls;
public event Action jumpEvent;
public event Action DodgeEvent;
private void Start()
{
Controls = new Controls();
Controls.Player.setCallbacks(this);
Controls.Player.Enable();
}
private void OnDestroy()
{
Controls.Player.Disable();
}
public void onJump(InputAction.CallbackContext context)
{
if (context.preformed)
{
jumpEvent?.Invoke();
}
}
public void onDodge(InputAction.CallbackContext context)
{
if (context.preformed)
{
DodgeEvent?.Invoke();
}
}
}
Firstly, let's get started with understanding the error, as that is the most important part of the problem.
'Inputreader' does not implement interface member 'Controls.IPlayerActions.OnDodge(InputAction.CallbackContext)'
What does this mean?
Let's start at the beginnning: The class InputReader apparently doesn't implement something. Why does it have to implement something?
Well, that is because of this line:
public class Inputreader : MonoBehaviour, Controls.IPlayerActions {
What does this line mean? It means that the class InputReader will have (Implement) all required methods and properties of the Interfaces/Classes MonoBehavior and Controls.IPlayerActions
In this case, IPlayerActions specify the following requirements:
Must have a public method OnJump which accepts InputAction.CallbackContext context as a parameter.
Must have a public method onDodge(InputAction.CallbackContext context) with the same sort of parameter.
Now back to the error, it specifies that this class is missing an implementation for OnDodge. Please note that everything in c# is case-sensitive. What does this mean?
public void onDodge is not the same as public void OnDodge.
What does the error specify?
Controls.IPlayerActions."OnDodge". What did you implement in your class? "onDodge". Do you see the difference?
Make sure the capitalization is correct for all implemented class members, or else you will get such errors.
I am working on a simple GUI framework, and I faced a problem calling protected virtual methods.
Here is the IKeyboardInputListenerService interface of service I use to receive keyboard events and the Control class that represents a base for all my GUI controls. The internal method is the one being refactored.
public interface IKeyboardInputListenerService
{
event EventHandler<KeyboardEventArgs> KeyPressed;
}
public abstract class Control
{
public IKeyboardInputListenerService KeyboardInputListenerService { get; }
protected Control(IKeyboardInputListenerService keyboardInputListenerService) =>
KeyboardInputListenerService = keyboardInputListenerService;
public event EventHandler<KeyboardEventArgs> KeyPressed;
/* protected */ internal virtual void OnKeyPressed(object sender, KeyboardEventArgs args)
{
if (enabled && visible && focused && !args.Suppressed)
{
KeyPressed?.Invoke(sender, args);
args.Suppressed = true;
}
}
public void Activate() =>
KeyboardInputListenerService.KeyPressed += new EventHandler<KeyboardEventArgs>(OnKeyPressed);
}
I also created a ContainerControl class that is supposed to contain child controls(like the Panel or GroupBox in Windows Forms) and that overrides the virtual method:
public abstract class ContainerControl : Control
{
private readonly ObservableCollection<Control> controls;
protected ContainerControl(IKeyboardInputListenerService keyboardInputListenerService)
: base(keyboardInputListenerService) =>
controls = new ObservableCollection<Control>();
/* protected */ internal override void OnKeyPressed(object sender, KeyboardEventArgs args)
{
foreach (Control control in controls)
control.OnKeyPressed(sender, args);
base.OnKeyPressed(sender, args);
}
}
Problem is, I cannot decide which modifier to use for methods such as OnKeyPressed. I wanted to make them protected, but it causes a compiler error:
Error CS1540 Cannot access protected member 'Control.OnKeyPressed(object, KeyboardEventArgs)' via a qualifier of type 'Control'; the qualifier must be of type 'ContainerControl' (or derived from it)
I can make them public, but I do not really think it is a good idea, because there is no reason for it except for resolving the problem caused by a cross-hierarchy call. I made them internal, but there is also a drawback: if anyone will want to create a user control, they will not be able to receive events, so the control will be useless.
The question is how to get access from a derived class to virtual methods of the base class without making the methods public-accessed.
Use protected internal
protected internal virtual void OnKeyPressed(object sender, KeyboardEventArgs args)
{ ... }
The documentation says:
protected internal The type or member can be accessed by any code in the assembly in which it is declared, or from within a derived class in another assembly.
I use Visual Studio 2015, and I have created a class diagram to have an overview of my most-used classes and their members.
I have a delegate defined in a class named UserMessage:
public delegate void ProcessUserMessage(UserMessage message);
I use this delegate in an other class:
public UserMessage.ProcessUserMessage ProcessUserMessage;
So far no problems.
Because I hate testing the callback for null every time, I hook up a no-op event handler at initialization, as suggested here:
public UserMessage.ProcessUserMessage ProcessUserMessage = delegate { };
But when I do that, and re-open the class diagram, it fails to load, saying:
Code could not be found for one or more shapes in class diagram 'ClassDiagram1.cd'. Do you want to attempt to automatically repair the class diagram?
The auto-repair doesn't work of course ;-(
Even when I place this initiatlization in the class' constructor, instead of at the declaration, the same error appears.
I fail to understand what's wrong. Any clues?
Update:
I created a blank project with just the failing code:
public partial class MainWindow
{
public UserMessage.ProcessUserMessageDelegate ProcessUserMessage = delegate { };
}
public class UserMessage
{
public delegate void ProcessUserMessageDelegate(string foo);
}
The strange thing is that the class diagram for MainWindow loads fine, but for UserMessage it fails. But I am not changing anythign for UserMessage.
It loads OK if I change class MainWindow to:
public partial class MainWindow
{
public UserMessage.ProcessUserMessageDelegate ProcessUserMessage;
}
Found the solution...
The anonymous no-op delegate must conform to the delegate definition, so all I had to add was add the argument ((string foo) in this example):
public partial class MainWindow
{
public UserMessage.ProcessUserMessageDelegate ProcessUserMessage = delegate (string foo){ };
}
public class UserMessage
{
public delegate void ProcessUserMessageDelegate(string foo);
}
I'm trying to do the following:
public abstract BaseClass {
public virtual void ReceiveEvent(Event evt)
{
ProcessEvent(evt as dynamic);
}
private void ProcessEvent(object evt)
{
LogManager.Log(#"Received an event that is not being processed!
Dispatch fallback");
}
}
public DerivedClass: BaseClass {
private void ProcessEvent(SpecificEvent evt)
{
LogManager.Log("Processing Event");
}
}
SpecificEvents hit the fallback method instead of the one in the derived class. I use dynamic dispatch within the same class all the time and find it really useful/clean. Will it not work with derived classes as illustrated in the example above?
EDIT:
There seems to be some confusion in the answers. Basically i use the following design all the time:
public class SomeClass{
public void DoSomethingDispatcher(SomeObject obj)
{
ProcessObject(obj as dynamic);
}
private void DoSomething(SomeObjectType1 obj)
{
}
private void DoSomething(SomeObjectType2 obj)
{
}
private void DoSomething(SomeObjectType3 obj)
{
}
private void DoSomething(object obj) //fallback
{
}
}
Works great for when you don't know the exact type beforehand and you don't want to use a big switch statement. Just wondering if this can be implemented with inheritance where the base class holds the fallback method and the derived class holds all the more specific methods.
It's not working for you because even if evt is passed dynamic, ProcessEvent is not declared as virtual. This means that when the call to ProcessEvent is compiled, it is linked to the only implementation of the method that is found in the base class, and the ones in the derived classes will never be executed. Furthermore, you can't simply declare your ProcessEvent as virtual, since the signature will be different in the derived classes.
In order for your code to work as expected you could just override ReceiveEvent in the derived classes leaving it exactly the same:
public override void ReceiveEvent(Event evt)
{
ProcessEvent(evt as dynamic);
}
If you want to manage the unhandled events in the base class, just change the modifier of Process event in the base class to protected (otherwise it can't be executed when called by the overridden version of ReceiveEvents).
If the method is not virtual/abstract in the base class, and the method is not marked as override in the derived class, it will never work.
Also, I dont understand the usage of dynamic here.
What is the type of your "evt" when it hit ProcessEvent ?
You may take a look to Using Type dynamic :
The type is a static type, but an object of type dynamic bypasses
static type checking. In most cases, it functions like it has type
object.
So, evt is not a SpecificEvent.
To get the expected behaviour you should override the virtual method:
public DerivedClass: BaseClass
{
private override void ReceiveEvent(Event evt)
{
// Process your event here.
}
}
With this code, ReceiveEvent in the base class won't be called, thus the fallback ProcessEvent won't be called.
There is no reason to use dynamic.
C# - .net 3.5
I have a family of classes that inherit from the same base class.
I want a method in the base class to be invoked any time a property in a derrived class is accessed (get or set). However, I don't want to write code in each and every property to call the base class... instead, I am hoping there is a declarative way to "sink" this activity into the base class.
Adding some spice to the requirement, I do need to determine the name of the property that was accessed, the property value and its type.
I imagine the solution would be a clever combination of a delegate, generics, and reflection. I can envision creating some type of array of delegate assignments at runtime, but iterating over the MemberInfo in the constructor would impact performance more than I'd like. Again, I'm hoping there is a more direct "declarative" way to do this.
Any ideas are most appreciated!
You can't do it automatically, but you can pretty much get 95% for free. This is a classic case for aspect-oriented programming. Check out PostSharp, which has the OnFieldAccessAspect class. Here's how you might solve your problem:
[Serializable]
public class FieldLogger : OnFieldAccessAspect {
public override void OnGetValue(FieldAccessEventArgs eventArgs) {
Console.WriteLine(eventArgs.InstanceTag);
Console.WriteLine("got value!");
base.OnGetValue(eventArgs);
}
public override void OnSetValue(FieldAccessEventArgs eventArgs) {
int i = (int?)eventArgs.InstanceTag ?? 0;
eventArgs.InstanceTag = i + 1;
Console.WriteLine("value set!");
base.OnSetValue(eventArgs);
}
public override InstanceTagRequest GetInstanceTagRequest() {
return new InstanceTagRequest("logger", new Guid("4f8a4963-82bf-4d32-8775-42cc3cd119bd"), false);
}
}
Now, anything that inherits from FieldLogger will get the same behavior. Presto!
I don't believe this is possible to do declaratively, i have never seen it done that way. What you can do though is implement the INotifyPropertyChanged interface on your base class, and have the implementation of the interface in the base class. Something like this:
public class A : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected virtual void RaiseOnPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName);
}
public A()
{
this.PropertyChanged += new PropertyChangedEventHandler(A_PropertyChanged);
}
void A_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//centralised code here that deals with the changed property
}
}
public class B : A
{
public string MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaiseOnPropertyChanged(this, "MyProperty");
}
}
public string _myProperty = null;
}