Moving get/set methods in another class - c#

Is it possible to move the get set methods in another class ?
I'm using an options form which basically reflects all the changes directly in the main form (mostly for changing controls colors,fonts and so on.
The issue starts when you start modifying quite a lot of controls since the main class fills with get set methods, so I was wondering if it's possible to refactor the code to increase the readability of the class a bit, or even better, if it's possible to move the methods in another class somehow (partial classes ?)
Here's a small example of just two controls
public Font TreeFont
{
get { return customTreeView1.Font; }
set { customTreeView1.Font = value; }
}
public Font TextBoxFont
{
get { return customTextBox1.Font; }
set { customTextBox1.Font = value; }
}
public Font MenusFont
{
get { return menuStrip1.Font; }
set
{
menuStrip1.Font = value;
statusStrip1.Font = value;
contextMenuStripForSnippetContent.Font = value;
contextMenuStripTreeViewMenu.Font = value;
}
}
public Color TreeFontForeColor
{
get { return customTreeView1.ForeColor; }
set { customTreeView1.ForeColor = value; }
}
public Color TextBoxFontForeColor
{
get { return customTextBox1.ForeColor; }
set { customTextBox1.ForeColor = value; }
}
public Color TreeFontBackgroundColor
{
get { return customTreeView1.BackColor; }
set { customTreeView1.BackColor = value; }
}
public Color TextBoxFontBackgroundColor
{
get { return customTextBox1.BackColor; }
set { customTextBox1.BackColor = value; }
}
So as you can imagine since there are quite a lot of them that need to be changed the lines just pile up.
In addition, would it be a better practice to just return the control and just work on that instead on the other form or do get/set methods considered a better practice ?
Thanks in advance.

If I understand you correctly - the problem is not the "class" but the "file". So you can simply split the class into two files (just like Visual Studio does with the InitializeComponent method) using Partial Classes.
Make sure the namespace is the same (If you create the file in a sub-folder you'll get a nested namespace. Simply change it.) Also, make sure your class begins with public partial class in both files. And don't have the same property declared in both classes.
Step by step instructions:
Right-click on your project in "Solution Explorer". Click "Add". Click "New Item". Click "class". Change class Class1 to public partial class Form1 : Form. Add using System.Windows.Forms; at the top of your file. Add your properties.

You can use either C# Regions to make a large code file manageable or you can use Partial Classes to split a large code file into multiple manageable files.

You could use a different kind of function that allows for Page.FindControl("controlNameHere"), and cast it in the right light. This is more for ASP.NET pages, not for Windows form, but you could find the same resolution here Find control by name from Windows Forms controls. This way you could pull the control name and manipulate without ever having to return anything.

Related

How can I change the Item Height in a checklistbox so the item text is not cut-off?

When I create a checklistbox on a form and populate the y's, g's, etc. get cut-off by the next item.
I've found similar questions answered from years ago (How to change CheckedListBox item vertical space) and tried implementing their fixes but there's not enough details to work it out.
Right now, I go to add -> new item -> class and add a class to my solution. The class looks like this
using System.Windows.Forms;
namespace Test_GUI
{
public sealed class MyListBox : CheckedListBox
{
public MyListBox()
{
ItemHeight = 30;
}
public override int ItemHeight { get; set; }
}
}
And the object appears in my toolbox like
this.
but once I drag and drop it to the form it gives me this
If anyone can point out what I'm doing wrong it would be a great help. This has frustrated me to no end. Thanks!
Unfortunately Visual Studio 2017 (2019?) still doesn't play nicely with 64-bit controls in the Toolbox. This is primarily because VS is a 32-bit application.
The normal solution is to build the project that contains your custom control(s) for the "Any CPU" platform. This might even mean creating a separate Class Library project to house them.
The quick and easy solution (subjective), is to add your custom control(s) to your Form in code and avoid the designer.
If changing ItemHeight is the only creative thing you want to do, I'll offer a workaround that uses the standard CheckedListBox control and reflection.
In your Form constructor, after the line InitializeComponent();, do the following:
var heightField = typeof(CheckedListBox).GetField(
"scaledListItemBordersHeight",
BindingFlags.NonPublic | BindingFlags.Instance
);
var addedHeight = 10; // Some appropriate value, greater than the field's default of 2
heightField.SetValue(clb, addedHeight); // Where "clb" is your CheckedListBox
This requires:
using System.Reflection;
This works because, internally, ItemHeight is a read-only property that returns Font.Height + scaledListItemBordersHeight.
[Updated by OP's comment]
If you need inherit some class, here is step for you.
Add user control to your project
Right click your project -> add -> User control. Visual studio will create 2 files.
(UserControl.cs and UserControl.Designer.cs)
Basically when you create user control, it inherit from UserControl.
So change it to CheckedListBox.
Add : base() at constructor as below.
Remove line to prevent compile error.
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
at UserControl.Designer.cs.
Add some properties, and if you set it public you can see it designtime as below picture.
If parent class need to be initialized, child class should add base() in constructor of your class.
And basic idea for design time action from Here
//Change parent class UserControl --> CheckedListBox.
//public partial class MyListBox : UserControl
public partial class MyListBox : CheckedListBox
{
/*
Add base() in your constructor.
*/
public MyListBox() : base()
{
InitializeComponent();
}
// Add some properties.
private int _ItemHeightOffSet = 0;
public int ItemHeightOffSet {
get { return _ItemHeightOffSet; }
set {
this._ItemHeightOffSet = value;
/*
This will help you adjust height in design time.
When 'DesignMode' is true --> Control loaded at Visual Studio. : Design time.
When 'DesignMode' is false --> Control loaded at debuging or running. : Run time.
*/
if (DesignMode == true)
{
base.ItemHeight = value + ItemHeightOffSet;
base.Refresh();
}
}
}
public override int ItemHeight
{
get {
return base.ItemHeight + ItemHeightOffSet;
}
set
{
base.ItemHeight = value + ItemHeightOffSet;
}
}
}

Re-evaluate all values in xaml page calculated by a markup-extension

In a xamarin app on a xaml page I am loading localized strings using a xaml extension (the details are described here). For example:
<Label Text={i18n:Translate Label_Text}/>
Now, I want the user to be able to change the language of the app at runtime (using a picker). If that happens, I want to change the language immediately.
Can I somehow reload all translated texts?
I could delete all pages and recreate them, but I am trying to avoid that.
I could also bind all localised texts to strings in the pages model. But that is a lot of unnecessary code for truly static strings.
Unfortunately you cannot force controls set up with markup extensions in XAML to reevaluate their properties using those extensions - the evaluation is only done once upon parsing XAML file. What basically happens behind the scenes is this:
Your extension is instantiated
ProvideValue method is called on the created instance and the returned value is used on the target control
The reference to the created instance is not stored (or is a weak reference, I'm not sure), so your extension is ready for GC
You can confirm that your extension is only used once by defining a finalizer (desctructor) and setting a breakpoint in it. It will be hit soon after your page is loaded (at least it was in my case - you may need to call GC.Collect() explicitly). So I think the problem is clear - you cannot call ProvideValue on your extension again at an arbitrary time, because it possibly no longer exists.
However, there is a solution to your problem, which doesn't even need making any changes to your XAML files - you only need to modify the TranslateExtension class. The idea is that under the hood it will setup proper binding rather than simply return a value.
First off we need a class that will serve as a source for all the bindings (we'll use singleton design pattern):
public class Translator : INotifyPropertyChanged
{
public string this[string text]
{
get
{
//return translation of "text" for current language settings
}
}
public static Translator Instance { get; } = new Translator();
public event PropertyChangedEventHandler PropertyChanged;
public void Invalidate()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Binding.IndexerName));
}
}
The goal here is that Translator.Instance["Label_Text"] should return the translation that your current extension returns for "Label_Text". Then the extension should setup the binding in the ProvideValue method:
public class TranslateExtension : MarkupExtension
{
public TranslateExtension(string text)
{
Text = text;
}
public string Text { get; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Mode = BindingMode.OneWay,
Path = new PropertyPath($"[{Text}]"),
Source = Translator.Instance,
};
return binding.ProvideValue(serviceProvider);
}
}
Now all you need to do is to call Translator.Instance.Invalidate() every time the language is changed.
Note that using {i18n:Translate Label_Text} will be equivalent to using {Binding [Label_Text], Source={x:Static i18n:Translator.Instance}}, but is more concise and saves you the effort of revising your XAML files.
I'd tried to implement #Grx70's great proposed solution, but some of the classes and properties the example used are internal to Xamarin so couldn't be used in that way.
Picking up on their last comment though, was the clue to get it working, though not quite as elegantly as initially proposed, we can do this:
public class TranslateExtension : IMarkupExtension<BindingBase>
{
public TranslateExtension(string text)
{
Text = text;
}
public string Text { get; set; }
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue(serviceProvider);
}
public BindingBase ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Mode = BindingMode.OneWay,
Path = $"[{Text}]",
Source = Translator.Instance,
};
return binding;
}
}
and this the Translator class as initially proposed, but reproduced here for clarity with the GetString call:
public class Translator : INotifyPropertyChanged
{
public string this[string text]
{
get
{
return Strings.ResourceManager.GetString(text, Strings.Culture);
}
}
public static Translator Instance { get; } = new Translator();
public event PropertyChangedEventHandler PropertyChanged;
public void Invalidate()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
}
Then as the original post suggested, instead of binding text with:
{i18n:Translate Label_Text}
Bind
{Binding [Label_Text], Source={x:Static i18n:Translator.Instance}}
I'd hit this right at the end of a project (adding the multiple languages), but using Visual Studio Community and Search/Replace with RegEx, the binding can be replaced across the project, replacing:
\{resources:Translate (.*?)\}
with:
{Binding [$1], Source={x:Static core:Translator.Instance}}
NOTE: The Regex assumes the 'resources' namespace for the original Translate macro, and 'core' namespace for the Translator class, you may have to update as appropriate.
I appreciate this is a small tweak to #Grx70's otherwise great solution (I'm standing on the shoulders of giants with this one), but I'm posting this here for any that follow with the same problem of getting this working.

Custom control / UIView in Xamarin.iOS with design-time properties

I am creating a user interface for an iOS app and I am looking for the correct way to create a reusable custom control. I got it generally working when running the app, but at design time setting my "exported" properties has no visible effect in the designer. I think I am doing something fundamentally wrong, so perhaps someone could give me guidance
What I am doing:
I have created a subclass of UIControl.
In the constructor I call an Initialize method.
In the Initialize method, I add several subviews and constraints to layout them within my control
Here is some hollowed out code that shows the above:
[Register("RangedValueSelector"), DesignTimeVisible(true)]
public sealed class RangedValueSelector : UIControl
{
public RangedValueSelector(IntPtr p)
: base(p)
{
Initialize();
}
public RangedValueSelector()
{
Initialize();
}
public int HorizontalButtonSpacing
{
get { return _horizontalButtonSpacing; }
set
{
_horizontalButtonSpacing = value;
}
}
[Export("LabelBoxVerticalInset"), Browsable(true)]
public int LabelBoxVerticalInset
{
get
{
return _labelBoxVerticalInset;
}
set
{
_labelBoxVerticalInset = value;
}
}
private void Initialize()
{
//Code that creates and add Subviews
//Code that creates and add the required constraints, some of which should depend on the design time properties
}
}
So the control works perfectly fine if I set the exported properties via the designer, however they do not have an immediate effect in the designer itself.
What is the suggested way of having design-time settable properties that change the constraint values? I would like to avoid having to recreate all the subviews each time someone in the code or in the designer sets a property.
You are missing constructor with RectangleF which is used by designer.
public RangedValueSelector(RectangleF bounds):base(bounds){}
The rest seems to be correct.

Getter and Setter in C# [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I'm just playing around with C# and I'm aksing myself which the proper method is for Getter and Setter. I found something like this with google:
class MyClass
{
Button btnMyButton;
// some code...
public Button getBtnMyButton
{
get
{
return btnMyButton;
}
}
}
is there a 'proper' way? Or is this also okay:
class MyClass
{
Button btnMyButton;
// some code...
public Button getBtnMyButton()
{
return this.btnMyButton;
}
}
Whats the difference?
As Thomas mentioned, those are the same things. You may wonder what the point of getter and setter is in that case and it's mainly syntactic sugar. However, it also means you don't have to create an explicit field as one is created for you in the background. Therefore, you can simply do
public Button MyButton { get; private set; }
The private set; ensures only the class can set its value so it's essentially read-only to outside classes. Removing the private will allow external classes to write to the variable too.
You usually do not add a get/set prefix to properties.
Just write it like that:
private Button myButton;
public Button MyButton{
get{
return myButton;
}
/*set{
myButton = value;
}*/
}
And yes, it means the same in your context. The this. would be required in this scenario:
(Note: This is a stupid example and should only show you the idea)
private Button myButton;
public Button MyButton{
get{
Button myButton = null;
return this.myButton; //<- this. is required or you would end up getting null all the time.
}
/*set{
myButton = value;
}*/
}
Edit:
Adding get/set comes from languages such as C++ or Java where you do not have the luxury of properties. Using get/set indicates a (heavy) operation. And the developer may think about caching the result instead of calling it numerous times. Only use get/set on methods where you want to specify a (heavy) operation. You may even end up using properties instead of methods if it is a very (easy) operation. In Intellisense (Visual Studio) a property is presented just like a field and thus we can assume that there is no operation going on. Thus I will (usually) never cache the result of a property.
On the other hand - if I find a property called GetResultOfImposible.
Then I would propably decide to cache that.
A property named ResultOfImposible sounds less heavy and I wouldn't cache it.
(Maybe I would change my mind after finding a performance peak)
You should think about the naming of the property a little more, because one property can have both a getter and a setter. Consider the following:
public class MyClass
{
private Button btnMyButton;
public Button getMyButton
{
get{ return btnMyButton; }
set{ btnMyButton = value; }
}
}
// in some other class
void ChangeActiveButton(Button newButton)
{
MyClass theThing = GetTheThing();
// This doesn't read well...
theThing.getMyButton = newButton;
}
When you implement property getters and setters, don't prefix the name with 'get' and set'. (To many developers, the words 'get' and 'set' in a method or function imply that the code has to go off and do some work to complete the getting or setting, rather than simply return or assign a value that is already to hand.)
public class MyClass
{
private Button btnMyButton;
// Note that the property just has a name, no prefix.
public Button MyButton
{
get{ return btnMyButton; }
set{ btnMyButton = value; }
}
}
Also note that you can make property getters and setters private even though the property itself is exposed outside the class.
public Button MyButton
{
get{ return btnMyButton; }
private set{ if(null == btnMyButton) btnMyButton = value; }
}
This provides the MyClass with priveliged access to the setter, which can be used to implement any property-specific assignment rules.
You can also use Auto-Implemented Properties, without the additional member variable.
public Button MyButton { get; private set; }
Properties in c# are great. Use them wisely and it will help you create better structured, more easily maintainable code.
Actually a getter/setter is nothing but a method returning/providing the internal value. So while writing
public Button getBtnMyButton
{
get
{
return btnMyButton;
}
}
you actually write a getter-method similar to this one:
public Button getBtnMyButton
{
return this.btnMyButton;
}
So the similar way in java is using methods.
That's the same, this call in is implicit.
The shorter you can do is:
class MyClass
{
// some code...
public Button getBtnMyButton { get; private set; }
}
And I recommend you a bit of reading : Auto-Implemented Properties (C# Programming Guide)
They're basically the same thing. The this pointer refers to the object that is calling the method.
A interesting thing about the this pointer is that it allows you to write set functions like
public void setMyButton (Button myButton)
{
this.myButton = myButton;
}
(Not sure if that's valid C# because I've never worked with it, but you get the idea. That should work in Java/C++)
The difference is in purpose. You should use property, when code just returns some value with few logic or without it at all. Also in general the value should be the same, if setter was not called. When the value is created (not stored) or logic is complex, you should use method. It is a good practice to create self-documented code.
The difference is that:
public Button getBtnMyButton()
{
return this.btnMyButton;
}
is a method, which can accepts inputs parameters and returns an output parameter.
The other:
public Button getBtnMyButton
{
get
{
return btnMyButton;
}
}
is a property. You can see a propery as a "wrapper" around a variable, that allow you to validate the variable value and to perform other kind of stuffs.
Example:
public Button getBtnMyButton
{
get
{
if (btnMyButton != null)
return btnMyButton;
throw new Exception("Button is null!");
}
set
{
if (value == null)
return;
btnMyButton = value;
}
}

Issues changing default backcolor in a usercontrol

I am creating a custom control with a black background but have some issues with the designer. Truth to be told I have a base control class that inherits from UserControl and then some subclasses that represent the final controls that I will use in my GUI. In that base class I override the BackColor property, add the DefaultValue attribute and set the default value to BackColor in the constructor. As an example my code looks something like this:
public partial class MyControl1 : UserControl
{
public MyControl1()
{
InitializeComponent();
BackColor = Color.Black;
}
[DefaultValue(typeof(Color),"Black")]
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
}
...
public partial class MyControl2 : MyControl1
{
public MyControl2()
{
InitializeComponent();
}
}
The thing is every time I open the designer for MyControl2, BackColor in the properties dialog reverts to System.Drawing.SystemColors.Control and my control is painted grey. If I invoke Reset on BackColor it properly returns to Color.Black, though. Also, the designer doesn't serialize the change to System.Drawing.SystemColors.Control until I make another change to the control.
So, what did I try?
I thought it could be related to BackColor being an ambient property so I tried adding the attribute AmbientValue(false). Of course it didn't work.
I tried erasing the overridden property, leaving only BackColor=Color.Black in the constructor. Surprisingly it fixed the problem with the designer but now resetting the property reverted it to a default value of System.Drawing.SystemColors.Control. Overriding ResetBackColor() didn't solve this last problem.
By the way, I am working under Visual Studio 2010 and my project was created as a .NET 2.0 Windows Forms Application.
I would be glad whether anyone could help me to find whatever is wrong in my code. It is not something that would prevent me from finishing the project but it is pretty annoying. Thank you very much in advance!
This may help - there appears to be some voodoo in the winforms designer (a bit like the XML serializer) that will look for properties which are named a specific way because the DefaultValue doesn't work as you might expect:
The following is an example from another post, I know you are not subclassing a DataGridView, but the principle ought to be the same.
public class MyGridView : DataGridView {
public MyGridView() {
this.BackgroundColor = DefaultBackgroundColor;
}
public new Color BackgroundColor {
get { return base.BackgroundColor; }
set { base.BackgroundColor = value; }
}
private bool ShouldSerializeBackgroundColor() {
return !this.BackgroundColor.Equals(DefaultBackgroundColor);
}
private void ResetBackgroundColor() {
this.BackgroundColor = DefaultBackgroundColor;
}
private static Color DefaultBackgroundColor {
get { return Color.Red; }
}
}
Incidently - this isn't my code - it's some more pure genius from Hans Passant... link to original with a full explanation: https://stackoverflow.com/a/20838280/685341

Categories

Resources