I added some extra stuff to the standard wpf combobox. In the constructor I set two properties:
public SmartComboBox()
: base()
{
this.IsEditable = true;
this.IsTextSearchEnabled = false;
...
}
The two properties are inherited from System.Windows.Controls.ComboBox.
How do I prevent the modification of these two properties after I set their values in the constructor?
Short answer: you can't, as that properties modifiers can not be changed by you.
If you want to hide an implementation, just encapsulate ComboBox class inside your class.
public class SmartComboBox {
private ComboBox _uiCombo = ....
}
And also in addition another thing yet:
In your example, in the code presented, there is no any reason of explicitly calling base() on ctor, as it will be called by CLR
You can't fully prevent it, the closest you can come is re-declaring the properties as new
public SmartComboBox()
{
base.IsEditable = true;
base.IsTextSearchEnabled = false;
...
}
public new bool IsEditable { get { return base.IsEditable; } }
public new bool IsTextSearchEnabled { get { return base.IsTextSearchEnabled; } }
The downside to this is that new is not an override, if the object is cast as its parent then the property can be set.
The other option is to wrap the class as Tigran mentioned, however the pita with that is exposing all the other properties you need.
What if you override the metadata for the IsEditableProperty and play with PropertyChangedCallBack and CorceValueCallBack? http://msdn.microsoft.com/en-us/library/ms597491.aspx
If IsEditable is marked as virtual, it should be trivial to just do
bool iseditableSet=false;
override bool IsEditable
{
get;
set
{
if(!iseditableSet){
iseditableSet=true;
base.IsEditable=value;
}else{
throw Exception...
}
}
If it's not marked as virtual, it's harder, but you can use "hiding" to prevent at least your own code from modifying the property without a very explict base. directive.. Of course, this is physically impossible to do though if you are dealing with a function that takes Combobox and it could possibly modify those properties. Just take it as a lesson why properties should almost always be virtual
Related
Given the following
class BaseClass
{
public int Property {get; protected set;}
}
class DerivedClass : BaseClass
{
public new int Property {get; set;} //Hides BaseClass.Property
public static DerivedClass Build()
{
var result = new DerivedClass
{
Property = 17;
//base.Property = 17; // this doesn't compile
}
//((BaseClass)result).Property = 17; // this doesn't compile
}
}
Is there any way to set BaseClass.Property from a static method inside the DerivedClass.
Reflection or Unsafe code is not what I want! I want a non hacky way of setting something which we do legally have access to, but I just can't work out how to set.
Here is how to access an overridden property from a static method of the class:
Add to the class a new property that accesses the base property:
private double BaseProperty { get => base.MyProperty; set => base.MyProperty = value; }
Use that new property from your static:
var result = new DerivedClass
{
BaseProperty = 17;
}
Here is a situation where the above technique is the cleanest solution I have found.
Consider XAML that refers to a BindableProperty, in a class library.
(In my case, the class library is Xamarin Forms.)
Without changing the property name, I want to decouple the base property (used by code compiled into the library) from the XAML-visible property (in my subclass).
The specific use is making text auto-fit, which X-Forms doesn't yet support.
The detail that is relevant here, is that I have the following BindableProperty declaration:
public new static readonly BindableProperty FontSizeProperty =
BindableProperty.Create("FontSize", typeof(double), typeof(AutofitLabel), -1.0,
propertyChanged: (BindableObject bindable, object oldValue, object newValue) => {
((AutofitLabel)bindable).BaseFontSize = (double)newValue;
});
which uses this private property:
private double BaseFontSize { get => base.FontSize; set => base.FontSize = value; }
What this accomplishes, is to initially set base.FontSize - which will be used by layout logic inside library's Label or other text-containing view - to the value set in XAML. Elsewhere in my subclass, I have logic that lowers base.FontSize as needed, once the available width/height are known.
This approach makes it possible to use the library without altering its source code, yet make it appear, to clients of my subclass, that auto-fitting is built-in.
It wouldn't be valid to change FontSize that is visible to client code - that represents the requested size. However, that is the approach taken by Charles Petzold in XF Book Ch. 5 "EmpiricalFontSizePage". Also, Petzold has the page itself deal with the auto-sizing - which is not convenient.
The challenge is the need to tell the library what actual FontSize to use.
Ergo this solution.
All other approaches I've found online require complex custom renderers, replicating logic already existing in XF library.
Is there any way to set BaseClass.Property from a static method inside the DerivedClass.
Yes, rethink your design. It is flawed. Hiding a property and then wanting to set the exact same value on the base and derived class? There seems something really wrong.
You don't necessarily need to hide the property, you could override it, but then it wouldn't make too much sense. It seems the only objective you have is to have different access modifiers on your base class and derived class. This goes against OOP rules, and should be avoided.
If you can introduce another intermediate class, then you can obviously do this. But as others have said, it doesn't just have a code smell, it's positively poisonous.
class BaseClass
{
public int Property { get; protected set; }
}
class InterClass : BaseClass
{
protected void DoFunnyStuff(int value)
{
this.Property = value;
}
}
class DerivedClass : InterClass
{
public new int Property { get; set; } //Hides BaseClass.Property
public static DerivedClass Build()
{
DerivedClass result = new DerivedClass
{
Property = 17
//base.Property = 17; // this doesn't compile
};
result.DoFunnyStuff(17);
return result;
//((BaseClass)result).Property = 17; // this doesn't compile
}
}
So DerivedClass does inherit from BaseClass still, but not directly. You can apply various tricks to try to minimize how much other code is exposed to the existence of InterClass.
It seems you want to modify the APIs behaviour in such a way that something which was mutable before should not be mutable any more. So why not defining a new property, which is really immutable and make the existing one Obsolete instead o trying to hide the original property but not hiding it?
class LegacyClass
{
[Obsolete("Use NewMember instead")]
public string ExistingMember { get; set; } // should actually be immutable
public string NewMember { get { ... } }
}
This way you donĀ“t break existing code.
Yes it's possible through reflection: Property hiding and reflection (C#)
No it's not possible in other ways, if you hide a property by design it's because you don't want give access to that from DerivedClass
Reflection allows you to access for particular purpose, it's not an hacky way the use of reflection.
It's an hacky way to access to a property that you have hidden by design.
If you want access in a legal way to a property you should not hide it.
Let say I have a class like this:
public class A
{
private BaseSettings fieldA;
public ISettings PropertyA
{
get {return fieldA;}
set {fieldA= value as BaseSettings;}
}
}
where BaseSettings implements ISettings. Inside class A, if I want to access BaseSettings' property called PropertyB, which of this is a good practice:
fieldA.PropertyB;
or
((BaseSettings)PropertyA).PropertyB;
One may say the first approach may hide the hint to when a property changed. For example, a code may listen to PropertyChangedEvent and then the value for property changed without raising the event.
Another one may say the second approach may expose a risk that when a person who is not familiar with current code modify it, he may cast the PropertyA to different type that implements ISettings.
Both approaches have its downside. In a good programming practice, which one should be more preferable?
EDIT:
Added based on the comments belows:
I agree that setting the backing-field as ISettings makes absolute sense. But what should I do to make sure that the PropertyA is always type of BaseSettings. That will raise a question: "Then why don't you set both property and backing-field to BaseSettings?".
The reason behind why property and its backing field are different is that class A also implement an interface like this
public interface IControlWithSettings
{
ISettings OwnerSettings
{
get;
set;
}
ISettings Settings
{
get;
set;
}
}
So the actual classA would look like this
public class BaseForm: Form, IControlWithSettings
{
private BaseFormSettings settings;
public ISettings Settings
{
get {return settings;}
set {settings= value as BaseFormSettings;}
}
}
And I have another class B would also implement IControlWithSettings
public class BaseUserControl: UserControl, IControlWithSettings
{
private BaseUserControlSettings settings;
public ISettings Settings
{
get {return settings;}
set {settings= value as BaseUserControlSettings ;}
}
}
Both BaseFormSettings : ISettings and BaseUserControlSettings : ISettings . This is actual ISettings interface
public interface ISettings
{
Dictionary<string, ISettings> Children { get; set; }
}
the 'as' casting is a side effect I put into the setter so that it will ignore and return null if the setting is set to wrong one. I read somewhere saying I shouldn't throw exception in a setter. So making it null is my way to inform there is something wrong has been done.
So what is the better approach. Did I design it wrong?
As you stated, both approaches have their downsides, and it also depends on whether the property setter may contain some additional logic (e.g. validation), and you may use or circumvent this additional logic from inside the class.
If there's nothing that speaks against it, I'll use direct access to the field. It's neater and it avoids all this typecasting stuff.
But generally: Why would you back your property with the derived type, while the property itself has the interface type? This doesn't make much sense. Why not just:
public class A
{
public ISettings PropertyA { get; set; }
}
This would be much cleaner, and your question wouldn't even arise.
Edit (based on the answer's edit)
In case of the 'double use' of the backing field the typecasting makes sense. But I don't think (and never heard that before) that it's a bad thing to throw an exception from a property setter. On the contrary: Validating a value and throwing an exception if it doesn't pass is a very common pattern.
So, in your concrete case, I would validate the value for the correct type, throw if it's not correct, and use the backing field internally to bypass this type check.
I relised I have lots of models view models with those two properties
public Visibility OkButtonVisibility
{
get{ return _OkButtonVisibility;}
set{
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
public Visibility CancelButtonVisibility
{
get{ return _CancelButtonVisibility;}
set{
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
I wanted to create attachable interface for them like this:
Interface IOKandCancelButtonsVM
{
public Visibility OkButtonVisibility
{
get{ return _OkButtonVisibility;}
set{
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
public Visibility CancelButtonVisibility
{
get{ return _CancelButtonVisibility;}
set{
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
and have my viewmodels that use this to inherite them and another interfaces with proxy properties like this
class VM1:BaseVM,IOKandCancelButtonsVM,IOtherCommonPropertyVM
{
}
but then I relaised my new interfaces don't impliment INotifyChanged.
would it be a bad idea to haveIOKandCancelButtonsVM impliment INotifyChanged
and have VM1 explicitly impliment BaseVM?
I never dealt with class inheriting same interface twice and not sure what to do.
this is only an example less than half of the VMs use those I have a few hundred properties, many shared over dozens of screens. i need a more elegant solution than sticking all on thos into the BaseViewModel
You cannot have an implementation in your interface definition. This means that your IOKandCancelButtonsVM definition is incorrect.
would it be a bad idea to have IOKandCancelButtonsVM impliment BaseVM
Yes it would be a very bad idea - impossible in fact - interfaces cannot implement or extend classes.
Since you asked for opinion on how to structure your code, I will also throw this out there: remove any reference to 'visibility' from your viewmodel. Do not return a System.Visibility value from your viewmodel.
A viewmodel shouldn't know anything about the view. The semantically correct way to do this is to simply return a flag from the viewmodel, and use a converter to change it to a Visibility value in the binding - there is even a ready made converter in the framework for doing this: BooleanToVisibilityConverter. Try to avoid any mention of UI related terms in your VM even if it is returning a bool - it is a good practice which leads to tighter and more disciplined code, using those names willy nilly will eventually lead to smelly code.
I have a blog post which illustrates a nice approach to property change notifications: Streamlining property notifications in MVVM.
Just to make it clear, I am advising that you get rid of any ideas you have about IOKandCancelButtonsVM interfaces, by all means include simple boolean properties on a base viewmodel that will be extended by many other viewmodels that will be bound to dialogs with OK/Cancel buttons.
To diagram this in text it would look like this:
YourBaseVm <-- BaseVmUsedByDialogs <-- SpecificDialogVm
(note the italicising which indicates the class is abstract)
It seems you already have a base viewmodel class. Just add the two properties there. You might want to create a second base inheriting from the first, which you use when those two properties are required, so in case their not, there is no overhead.
Why not to go for virtual properties in your base class BaseVM with default functionality implemented in it. In case other derived classes want to extend it they can always override it as per funcitonality required.
Make sure your BaseVM is implementing INotifyPropertyChanged.
I'd just create an abstract base class, and have the ViewModels that need those properties inherit from it. Keep it simple.
abstract class BaseDialogVM : BaseVM
{
private Visibility _OkButtonVisibility;
public Visibility OkButtonVisibility {
get { return _OkButtonVisibility; }
set {
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
private Visibility _CancelButtonVisibility;
public Visibility CancelButtonVisibility {
get { return _CancelButtonVisibility; }
set {
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
}
class VM1 : BaseDialogVM { /*...*/ }
So I've got these classes that expose a collection of child objects.
I don't want other classes adding or removing objects from collections because I need to wire into events in the child objects, so as they get added or removed I want to be able to do additional processing. But I really love the ease of manipulating generics internally.
Did I mention this is a WPF app so I need INotifySupport?
The best I can come up with is something like this.
public class foo : INotifyPropertyChanged
{
protected List<ChildFoo> _Children = new List<ChildFoo>();
public foo()
{
}
public void AddChild(ChildFoo newChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
public void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo[] Children
{
get
{
return _Children.ToArray();
}
}
}
Are there serious flaws with this design that I'm not seeing?
Every time the Children property is accessed we get the overhead of converting list to an array.
Any advice on this would be great.
This is what I do for normal code:
Public Readonly Property Childern As ObjectModel.ReadOnlyCollection(Of Child)
Get
Return New ObjectModel.ReadOnlyCollection(Of Child)(_ChildernList)
End Get
End Property
For WPF code I would just expose a subclass of ObservableCollection.
You should use ObservableCollection as field in your class, you then have full access to modify collection. Then expose this as ReadonlyObservableCollection via property.
And if you dont change collection itself (eg. nochildren = new ObservableCollection(), you should make field readonly), then you dont need any kind of notifyPropertyChanged on this property, because it doesnt change and collection itself handles those events for its children.
public class Child
{
public int Value { get; set; }
}
class MyClassWithReadonlyCollection
{
private readonly ObservableCollection<Child> _children = new ObservableCollection<Child>();
public MyClassWithReadonlyCollection()
{
_children.Add(new Child());
}
//No need to NotifyPropertyChange, because property doesnt change and collection handles this internaly
public ReadOnlyObservableCollection<Child> Children { get { return new ReadOnlyObservableCollection<Child>(_children); } }
}
I changed the "add child" and "remove child" to protected since you are saying you don't want other classes modifying your collection. I changed your List to ObservableCollection so you can recieve collection changed notifications. Since you are using an IList there is no need to call ToArray(), just access directly.
try this:
public class foo : INotifyPropertyChanged
{
protected ObservableCollection<ChildFoo> _Children = new ObservableCollection<ChildFoo>();
public foo() { }
protected void AddChild(ChildFoo oldChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
protected void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo this[int n]
{
get
{
return _Children[n];
}
}
}
You could subclass BindingList and set AllowNew/AllowRemove to false. In your Child Add/Remove methods, you can set it to true, make the changes, then set it back to false. (Of course, you need to hide set access to AllowNew/AllowRemove from outside callers as well).
Another option - subclass Observable collection and override the InsertItem, RemoveItem, etc methods to behave as AddChild/RemoveChild would behave. Then callers can still access it in familiar ways, but not bypass your custom logic.
Subclassing an existing collection class is probably going to be easier (for you and the consumer) than wrapping a collection in another class.
I am using a class that I cannot edit, it has a property (a boolean) of which it would be nice to be informed when it changes, I can't edit the properties get or set as I am importing the class from a .dll (which I don't have the code for).
How do I create an event/function that is fired when the property is changed?
Additional
It is only changed within its own class, directly to the underlying private variable.
E.g.
private bool m_MyValue = false;
public bool MyValue
{
get { return m_MyValue; }
}
private void SomeFunction()
{
m_MyValue = true;
}
You can't, basically... not without using something like the debugger API to inject code at execution time and modifying the IL of the original library (and I'm not recommending either of those solutions; aside from anything else it may violate the licence of the library).
Basically if a property doesn't support notification, it doesn't support notification. You should look for a different way of approaching your problem. (Would polling work, for example?)
You cant do this directly [as Jon Skeet said], unless it's virtual, you're in a position to intercept all instance creations of the class and there are no changes to a backing field that influences the real 'value' of the propget.
The only way to brute force this is to use Mono.Cecil or MS CCI to instrument the prop setter a la this DimeCast on Cecil. (Or PostSharp)
However this wouldn't trap internal changes to the backing field (if there even is one). (Which is why wrapping probably wont work).
UPDATE: Given your update that you're definitely trying to trap the underlying field change, the only way to do that is to use PS / CCI / Cecil and analyse the flow to intercept all field updates. In short, not very feasible.
Arguably, the only real way to do this is to create some kind of "watcher" component, running in a separate thread, whose job is to read the property at intervals and raise an event when the property's value changes. Of course this solution sails in the murky waters of threading and synchronization.
On the assumption that your application is single-threaded in respect to this object, your cleanest solution is to make method calls to this object via a proxy object. It would have the job of checking the before and after state of the property and raising an event in the case it has changed.
Here's a simple example of what I'm talking about:
public class SomeProxy
{
public SomeProxy(ExternalObject obj)
{
_obj = obj;
}
public event EventArgs PropertyChanged;
private bool _lastValue;
private ExternalObject _obj;
protected virtual void OnPropertyChanged()
{
if(PropertyChanged != null)
PropertyChanged();
}
protected virtual void PreMethodCall()
{
_lastValue = _obj.SomeProperty;
}
protected virtual void PostMethodCall()
{
if(_lastValue != _obj.SomeProperty)
OnPropertyChanged();
}
// Proxy method.
public SomeMethod(int arg)
{
PreMethodCall();
_obj.SomeMethod(arg); // Call actual method.
PostMethodCall();
}
}
Obviously you can build this proxy pattern into a suitable object - you just have to be aware that all calls have to go through the proxy for the event to be raised when you expect it to be.
As previously mentioned, the most direct method (and that which requires the least change to code) is to use an AOP library such as PostSharp.
However, a solution can be achieved using traditional C#/.NET by using the dependency property pattern, used throughtout WPF to great effect. I suggest to read up on this, and consider implementing such a system (or at least a simplified version of it) for your project, if appropiate.
You will need to create a class that wraps the class in the dll, within the setter property just raise an event there using the normal methods.
Could you inherit from the class and hide the property? Something like this...
class MyClass : BaseClass
{
// hide base property.
public new bool MyProperty
{
get
{
return base.MyProperty;
}
set
{
base.MyProperty = value;
RaiseMyPropertyChangedEvent();
}
}
}
I think Alex' idea of a wrapper is good, however, given that the most important thing to you is that you know that the value is changed before use, you could simply move the notification to the getter, circumventing the worries of internal value change. That way you get something similar to polling, yet reliable:
class MyClass : BaseClass
{
//local value
private bool local;
//first access yet?
private bool accessed = false;
// Override base property.
public new bool MyProperty
{
get
{
if(!accessed)
{
// modify first-get case according to your taste, e.g.
local = base.MyProperty;
accessed = true;
RaiseMyPropertyChangedBeforeUseEvent();
}
else
{
if(local != base.MyProperty)
{
local = base.MyProperty;
RaiseMyPropertyChangedBeforeUseEvent();
}
}
return local;
}
set
{
base.MyProperty = value;
}
}
}
You can try to inherit it and use it's child instead of it.
Override the "set" of the property so it raises the event.
EDIT: ... only if property is virtual in the parent class ...