I'm trying to make a class inherited from another class that I don't have access to.
public class MyLabel : Label
{
public MyLabel()
{
base.Text = "This text is fixed";
base.BackgroundColor = Color.Green;
}
}
The Text and Visible properties are still available when calling like this:
MyLabel lbl = new MyLabel();
lbl.Text = "Nope.";
lbl.BackgroundColor = Color.Red;
Is there a way to make these two last statements invalid?
You can hide the inherited properties using the new keyword and redefine them as readonly.
public class MyLabel : Label
{
new public string Text { get { return base.Text; } }
new public string BackColor { get { return base.BackColor; } }
public MyLabel()
{
base.Text = "This text is fixed";
base.BackColor= Color.Green;
}
}
Inheritance is inheritance. If your parents passed you the trait for blue eyes, the trait is in your genetic code. That doesn't mean you have blue eyes, though. While you inherit the trait, you might have brown eyes (dominant trait) and therefore you express that trait instead.
Code works similarly. If foo inherits from bar, every foo will have the traits of a bar. What you can do, however, is override the traits with traits unique to the class.
public override string Text
{
get { return "Nope"; }
set { return; /*or throw an exception or whatever you want to do*/ }
}
Now that I've show you how, don't do it if you can avoid it. If you're worried about inheriting a complex object like a Label and you don't want to expose some of what it inherits, your problem probably has nothing to do with with the modifiers on the properties, and everything to do with the scope modifier on your actual instance. You'd be better off using the object in a more narrow scope, then letting it fall out of scope before anything else would access it.
The reason you want to avoid this is code smell. Lets say you make a class library that uses your MyLabel. Because it inherits from Label, I know I can use it just like a label. Then, when I do this:
MyLabel myLanta = new MyLabel();
myLanta.Text = "Oh!";
...I will then proceed to spend an hour trying to find out why myLanta's text is always "Nope!" This is why it's important to throw an exception here, or at least use a summary so when another person is coding, they can see at a glance that no matter what they assign for "Text", it will always be "Nope".
My recommendation is that if you need to narrow the available properties of a class, make the class a component of a new class instead of inheriting it.
public class MyLabel
{
private System.Windows.Forms.Label label
= new System.Windows.Forms.Label { Text = "Nope", BackColor = Color.Green };
//a public accessor and setter
public Font Font { get { return label.Font; } set { label.Font = value; } }
//only this class can set the color, any class can read the color
public Color ForeColor { get { return label.ForeColor; } private set { label.ForeColor = value; } }
public AllMyStuffIWantToDo()....
//fill in your stuff here
}
Then, if you want to return properties of the Label, you can with methods and properties you control without having to worry about inheritance issues. If you don't provide an accessing method to the Label's property, that property never sees the light of day and is effectively private to the class. This also prevents broken code from someone passing your MyLabel in place of a Forms.Label because that inheritance contract will not exist.
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.
I am developing a set of custom controls for a specific application. I want to define properties which is universal over the set of controls for appearance purposes, for argument's sake let's make it CustomCtrl.AccentColor
I want to define that same property for my Windows form i.e. Form1.AccentColor and when I change it, all the custom controls' AccentColor should change, exactly like when I change the ForeColor of my form, all labels' and buttons' etc ForeColor changes with it.
Is it at all possible to do this or do I have to settle for the effort of looping through all custom controls and changing it one-by-one?
Short Answer
Since you can have a common base class for all your controls as you mentioned in comments, as an option you can create a base class and then add some properties with behavior like ambient properties (like Font) to the base control class.
Detailed Answer
An ambient property is a property on a control that, if not set, is retrieved from the parent control.
In our implementation, we get the value from parent Form using FindForm method. So in the implementation, when getting the property value, we check if the value equals to default value and if the parent from has the same property, we return the property value of the parent form, otherwise we return the property value of the control itself.
After adding XXXX property, in this scenario we also should implement ShouldSerializeXXXX and ResetXXXX methods to let the designer when serialize the property and how to reset value when you right click on property and choose reset.
MyBaseControl
using System.Drawing;
using System.Windows.Forms;
public class MyBaseControl : Control
{
public MyBaseControl()
{
accentColor = Color.Empty;
}
private Color accentColor;
public Color AccentColor
{
get
{
if (accentColor == Color.Empty && ParentFormHasAccentColor())
return GetParentFormAccentColor();
return accentColor;
}
set
{
if (accentColor != value)
accentColor = value;
}
}
private bool ParentFormHasAccentColor()
{
return this.FindForm() != null &&
this.FindForm().GetType().GetProperty("AccentColor") != null;
}
private Color GetParentFormAccentColor()
{
if (ParentFormHasAccentColor())
return (Color)this.FindForm().GetType()
.GetProperty("AccentColor").GetValue(this.FindForm());
else
return Color.Red;
}
private bool ShouldSerializeAccentColor()
{
return this.AccentColor != GetParentFormAccentColor();
}
private void ResetAccentColor()
{
this.AccentColor = GetParentFormAccentColor();
}
}
MyBaseForm
public class BaseForm : Form
{
[DefaultValue("Red")]
public Color AccentColor { get; set; }
public BaseForm()
{
this.AccentColor = Color.Red;
}
}
Form1
public partial class Form1 : BaseForm
{
public Form1()
{
InitializeComponent();
}
}
i think you can create inherited class from Control class and define your common properties on there then inheriting your custom controls from that class and use parent property to access container (like Form) and get property value from it
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
In a base class I have this property:
public virtual string Text
{
get { return text; }
}
I want to override that and return a different text, but I would also like to be able to set the text, so I did this:
public override string Text
{
get { return differentText; }
set { differentText = value; }
}
This however does not work. I get a red squiggly under set saying that I can not override because it does not have a set accessor. Why is this aproblem? What should I do?
public virtual string Text
{
get { return text; }
protected set {}
}
change base class property like this, you are trying to override set method that doesn't exist
In your second block of code you are creating a public set method, but the word "override" in the declaration makes the compiler look for a method with the same signature in the base class. Since it can't find that method it will not allow you create your set.
As ArsenMkrt says you could change your base declaration to contain a protected set. This will allow you to override it, but since you still won't be able to change the signature you can't promote this method to public in your subclass, so the code you posted still won't work.
Instead you either need to add a public virtual set method to your base class that doesn't do anything (or even throws an exception if you try and call it) but this goes against what a user of the class would expect the behaviour to be so if you do this (and I won't recommend it) make sure it is so well documented that the user can't miss it:
///<summary>
///Get the Text value of the object
///NOTE: Setting the value is not supported by this class but may be supported by child classes
///</summary>
public virtual string Text
{
get { return text; }
set { }
}
//using the class
BaseClass.Text = "Wibble";
if (BaseClass.Text == "Wibble")
{
//Won't get here (unless the default value is "Wibble")
}
Otherwise declare the set as a separate method in your child class:
public override string Text
{
get { return differentText; }
}
public void SetText(string value)
{
differentText = value;
}
You want more capabilities to be exposed when using a child type. It sounds like you don't want to override, you want to shadow. Just use the new keyword to hide the readonly Text property under your readable/writable property.
In base class:
protected string text;
public string Text
{
get { return text; }
}
In derived class:
new public string Text
{
get { return text; }
set { text = value; }
}
It's a problem because you are breaking the encapsulation. You can't override something and make it more accessible, that would throw everything about encapsualtion out the window.
That's the rule and it applies in your case also, eventhough you are actually exposing something that is not the original value.
There is no way to do exactly what you attempted. You have to either make a setter in the base class, or use a different method of setting the new value.
You could hide the property from the base class :
public new string Text
{
get { return differentText; }
set { differentText = value; }
}
But in that case that property will only be used when manipulating the object through a variable of this type, not the base type
How can I make a textbox in my winforms application that accepts new lines of text from anywhere in the application?
I have a main form that contains a textbox. I'd like to directly add text to the box from a method in another class.
Update
I tried this in my main form:
public void Output(String value)
{
if (txtOutput.Text.Length > 0)
{
txtOutput.AppendText(Environment.NewLine);
}
txtOutput.AppendText(value);
}
But I can't call Output from the other class. I'm new to C#, so perhaps I'm missing something obvious.
Regards, Miel.
PS Yes, I know this is bad design, but for now this seems to be the best way to do what I want. The textbox would function like a console.
You'll need to expose the Text property of the TextBox as a string property on your form. For example...
public string TextBoxText
{
get { return textBoxName.Text; }
set { textBoxName.Text = value; }
}
Edit
After reading the question edit, your problem is that you need a reference to a specific instance of the form whereever you're trying to execute that code. You can either pass around a reference (which is the better option), or you could use some smelly code and have a static property that refers to one instance of your form. Something like...
public partial class MyForm : Form
{
private static MyForm instance;
public static MyForm Instance
{
get { return instance; }
}
public MyForm() : base()
{
InitializeComponent();
// ....
instance = this;
}
}
Using this approach, you could call MyForm.Instance.Output("test");
In order to decouple a bit more you could inverse the control a bit:
// interface for exposing append method
public interface IAppend
{
void AppendText(string text);
}
// some class that can use the IAppend interface
public class SomeOtherClass
{
private IAppend _appendTarget = null;
public SomeOtherClass(IAppend appendTarget)
{
_appendTarget = appendTarget;
}
private void AppendText(string text)
{
if (_appendTarget != null)
{
_appendTarget.AppendText(text);
}
}
public void MethodThatWillWantToAppendText()
{
// do some stuff
this.AppendText("I will add this.");
}
}
// implementation of IAppend in the form
void IAppend.AppendText(string text)
{
textBox1.AppendText(text);
}
It looks like your design is a little bit corrupted. You shouldn't let buisness logic mess with GUI controls. Why don't you try a return value and assigning it on the interface side?
This is a REALLY bad way of doing it, but just to make sure all the answers are out there...
In the VS designer, each form control has an item in the Properties window named Modifiers that defaults to Private. Changing this to one of the others settings, such as Internal or Public, will let you access it from outside the form.
I must stress that this is the worst way to do it.