Fody.PropertyChanged doesn't fire on inherited Property - c#

I have a Control which inherits from NumericUpDown in WinForms.
I want to handle changes to the DecimalPlaces-Property of NumericUpDown, therefore I have both tried declaring a
void OnDecimalPlacesChanged()
{
MessageBox.Show("Moeeep");
}
and also manually subscribing the PropertyChanged-event in the ctor manually. It seems to just not fire when I update DecimalPlaces and I have no idea why.

Since Control does not implement INotifyPropertyChanged, only your class does. Because of that, the Control doesn't raise any event when the DecimalPlaces changes. No framework can inject that into their code.
For now, the best thing you have is to override the UpdateEditText method. It is called when the DecimalPlaces property changes. Note that this is of course not the only reason the method is called, so you might have a problem there...

Related

Raise CanExecuteChanged when the model changes

In my ViewModel I have an ObservableCollection of Person objects (that implement INotifyPropertyChanged) and a SelectedPerson property. These are bound to a ListBox in my view.
There is also the following Prism DelegateCommand in my ViewModel:
Private DelegateCommand _myCommand = New DelegateCommand(CanExecute)
Public DelegateCommand MyCommand {get {return _myCommand;}}
Private Bool CanExecute()
{
Return (SelectedPerson.Age > 40);
}
What is the most elegant way of calling MyCommand.RaiseCanExecuteChanged whenever the SelectedPerson changes and whenever the SelectedPerson's age changes?
Adding and removing property changed handlers in the SelectedPerson's setter seems a bit messy to me.
Adding and removing property changed handlers in the SelectedPerson's setter seems a bit messy to me.
That's how I do it, and I'm not sure what a cleaner alternative would be. If the command state depends on a sub-property, you need to observe the changes somehow. Be careful about unsubscribing, though, or you risk a memory leak if your Person outlives your view model. PropertyChangedEventManager and weak event handlers can help if you can't guarantee that you unsubscribe.
To keep things clean, I usually just have one handler that listens for any sub-property changes, which calls a RequeryCommands method (also called directly by view model methods), which in turn invokes RaiseCanExecuteChanged for all the commands in my view.

VCL's CustomControl equivalent in Windows Forms

Delphi's VCL has a very useful class, CustomControl. This class is a direct base class of Control, which is equivalent to C# WF's UserControl.
For those, who are not familiar with VCL, CustomControl differs very little from Control; the main difference is that most of properties are protected; when implementing the new control, developer may decide, which ones does he want to publish and which ones shall remain hidden.
I'm developing my own control for Windows Forms and I want to hide some properties and events. For instance, I don't want to expose the MouseDown event - instead I allow capturing clicking on control's elements.
Is there an equivalent of VCL's CustomControl in Windows Forms? If not, how can I hide unwanted public properties and events in my control?
In response to answers:
This is not a matter of security, but rather a matter of code elegance. In Delphi I can derive from CustomControl, leave the OnMouseDown event protected (as in C#'s protected) and say to the control's user:
You cannot use OnMouseDown, because there is none. If you want to react to user clicking on control, simply use OnElementClicked - you'll even get detailed information about which element was clicked and what was its state.
I may disable calling the MouseDown event as Hans Passant suggested, but then I would have to include the following in the control's user's manual:
Please do not use the MouseDown event, because I've overridden the OnMouseDown method, such that it won't call the MouseDown event. This is because the control's logic is designed in such way, that you should use OnElementClicked rather than OnMouseDown. Please don't criticize the control because of MouseDown not working. Please don't report it as a bug, because it is by design. Please don't post messages in forums or create blog entries explaining how to fix the MouseDown problem by inheriting the class and manually calling the MouseDown event, because it would break the control's logic. Pleas don't... damnit, told you so!
If someone actually inherits from my control - I assume then, that he knows, what he's doing (also because one would then gain access to my control's internal logic as well). But if someone just uses my control, I would give him only these properties, events and methods, that I'm sure will work as designed.
I hope it explains my motives :)
There's a fundamental difference between hiding, what you asked for, and making it inaccessible, what I assume Delphi does. Hiding is simple, just repeat the declaration and apply attributes:
using System;
using System.ComponentModel;
using System.Windows.Forms;
class MyControl : Control {
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
private new event MouseEventHandler MouseDown;
}
Which prevents the event from being displayed in the Properties window, it won't show up in the IntelliSense dropdown and generates a compile error when he tries to assign the event in code anyway.
It is however not an absolute guarantee that the client programmer couldn't work around the restriction anyway. By casting or overriding your class for example. But the ultimate backdoor is implementing the IMessageFilter interface, nothing you can do about that. So this ought to be good enough if elegance is the goal.

Override AppendText

I made my own custom TextBox control, but now I need to add the AppendText property, does anyone have any idea how to do this? I can't seem to find any information about this on Google, I can only find how you use it, not how you implant it in a custom control.
Here is the code of the TextBox if anyone is interested http://pastebin.com/iW4xQCai.
In general, you would be much better off inheriting directly from TextBox instead of creating a composite control.
Either way, there should be no problem implementing the AppendText method (there is a difference between a method and a property).
If you are not overriding TextBox, simply add a new method to your class which passes the call to your textbox.
public void AppendText(string txt)
{
textBox.AppendText(txt);
}
If you are overriding TextBox, this would require absolutely no code as the method would already be inherited.

ComboBox changed before Window is loaded

I have a WPF / XAML Window that contains a ComboBox that is giving me problems.
The window's ComboBox is firing off the SelectionChanged event.
The Debugger callstack shows me that SelectionChanged is being called (indirectly) from the Window Constructor.
The problem is that the window has an event Window_Loaded, which does some final initialization of data-members. Because this final initialization isn't done yet, the SelectionChanged event fails with a null-reference exception.
There are several ways I could solve this, but I'd like to know the "most correct" way.
I could fully initialize all my data members in the constructor. This violates the concept of keeping constructors minimal.
I could code the SelectionChanged event handler to properly deal with some data-members being null. This is coding to deal with only a startup problem that will never occur once the Window is fully constructed.
I could make the data-members Lazy-Loaded, so they are not initialized by Window_Loaded, but rather when they are first accessed. Seems like a bit of work to solve a problem that could be solved more simply.
I assume I'm not the first person to deal with UI-events prior to the Window Loaded event. What is the preferred way to handle this?
I had a similar problem and while tracing through it I had an "a-ha" moment. I had a default value as "IsSelected", an OnChange event, and a custom loadSettings method. I blamed the settings method at first, but it turned out that having a default value selected triggered the OnChange event before a handful of the controls were loaded, including the parent combobox which was triggering the null reference. Once I removed the "IsSelected" and allowed the default value to be null/empty it worked fine and my loadSettings method took care of setting the default or last used value.
I usually deal with the (endlessly irritating) SelectionChanged problem like this:
bool mySettingSelectionChangedInCode;
private void SetMySettingComboBox(string value)
{
mySettingSelectionChangedInCode = true;
mySettingComboBox.SelectedItem = value;
mySettingSelectionChangedInCode = false;
}
private void mySettingComboBox_SelectionChanged(object sender, EventArgs args)
{
if (mySettingSelectionChangedInCode)
return;
//...
}
The most proper way would be to build your application using MVVM pattern. In that case you would not have to deal with those problems. But I realize that it is not always possible to just move to MVVM unless the project is in its very beginning state.
Anyway, the problem you describe I would solve by defining a flag like IsInitialized in your window and set it to true once you've completed the initialization in the Loaded event handler. Then, I would check that flag in the SelectionChanged handler and if it is False then return from method without doing anything (ignore the call).
This worked for me:
if (System.Windows.Application.Current.MainWindow.IsInitialized == true)
{
//Do something
}
This could happen because you've set the SelectedValue of the combobox after setting the ItemsSource property.

How to bind event to event handler of the member field or property using XAML?

Let's say I have window and I would like to handle Closed event. This is trivial:
Closed="Window_Closed"
this assumes I have Window_Closed event handler within my window. But what if I have a member (field)
public MySophisticatedEventHandler event_handler { private set; get; }
in my window, and I would like to set it like this:
Closed="event_handler.Window_Closed"
'event_handler.Window_Closed' is not a
valid event handler method name. Only
instance methods on the generated or
code-behind class are valid.
Question -- is there any clever way to do this using XAML? For now I set it in code, but I prefer XAML for such things.
Edits
1
Just for the record. In code you simply write:
Closed += event_handler.Window_Closed;
IOW, I am looking for direct equivalent of this for XAML.
What I typically would do is to put the sophisticated method in my ViewModel and then call it from my code behind of the view. You can use commanding to bind to commands through XAML, but IMO its usually not worth the effort unless your using one of the built-in commands.
you can't on WPF prior to 4.5 because event handler don't support markup extension. but with 4.5 you possibly do that check here for explaination and here for implementation

Categories