finding the best way to apply a property to the code - c#

sorry for confusing title.
I am using a thirdparty contorl for Spreads and it has a comboBoxCellType().
In my code there are like 20 places that I have a code like this:
ComboBoxCellType cbo = new ComboBoxCellType()
cbo.OtherStuff...
now I want all the occurences of such codes to have an extra property called listwidth =0; so
something like:
ComboBoxCellType cbo = new ComboBoxCellType()
cbo.listwidth=0;
cbo.OtherStuff
one way is just to search the code and add it manually. but I was wondering is there a better way using Inheritance and overriding to do this?

You can create a static class that can be used to new up the ComboBoxCellType.
Something like this:
public static class ComboBoxCellTypeFactory
{
public static ComboBoxCellType Create()
{
return new ComboBoxCellType(){listwidth = 0};
}
}
With this you can new up ComboBoxCellType instances with the listwidth property set to 0 like this:
ComboBoxCellType cbo = ComboBoxCellTypeFactory.Create();
cbo.OtherStuff...

Encapsulate the creation and initialization of a ComboBoxCellType to a method and call that method from every place you previously did this.
In general, if you find yourself repeating code, see if you could extract the code into a method that you can call. Keep your code DRY.
Something like:
private ComboBoxCellType BuildComboBoxCellType()
{
ComboBoxCellType cbo = new ComboBoxCellType()
cbo.listwidth=0;
cbo.OtherStuff...
return cbo;
}
And in your original code:
ComboBoxCellType cbo = BuildComboBoxCellType();

If you have access to the source code I would suggest placing a this.listwidth = 0 in the constructor of your ComboBoxCellType.

Related

How to create a type that Is just a variable containing another type?

Sorry for my verry badly written title, I'm a beginner programmer and I just started on a c# winforms app. In one function I create an object of some type and then in other functions I iterate through a list of that type of objects, however I'm switching the type of control I'm using and when I do, I have to change the type declaration of my object in over twenty places. Is there a way to create a variable that holds that type and than define all my objects off that variable so I only have to specify the type once and then change that variable. Because I'm using winforms controls as my class types all the functions I call are all then same no matter what type my objects are, so all I need to do is change the type declaration and that's it, sorry if this is a stupid question and any help would be appreciated.
Here is a snippet of my code for context:
private void function1(object sender, EventArgs e) //not my actual function because the real function has lots of other unrelated code
{
ListView PlaceType = new ListView(); // these ListView types i would like to replace with a placeholder if possible
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().ToList().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" + count2;
listview.MouseDown += Select;
}
private void function2(object sender, EventArgs e)
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
private void function3(object sender, EventArgs e) // I have several functions like this
//and if I change the control I'm using I have to change the types in every function
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
If I understand your problem correctly, you currently have some code where you use a ListView, and you want the same code, but instead of ListView you want some other class, for instance a DataGridView, or a ComboBox. Of course this other class must also have the methods that you used on the ListView.
In C# this concept is called a generic. You have generic classes and generic methods.
You define the generic by typing an identifier instead of the part that you want to replace with another type.
In your case: you want to replace ListView by DataGridView. In function1 you create a ListView, and set some properties. First we'll put this creation in a separate method, you will have something like this:
private ListView CreateListView()
{
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" + count2;
listview.MouseDown += Select;
return listView;
}
private void function1(object sender, EventArgs e)
{
ListView createdListView = this.CreateListView();
// TODO: do something with the created ListView
}
(Small optimization, out of scope of the question): to calculate count2, don't create a List of all ListViews, and then Count them; use Count() on the IEnumerable<ListView>.
To change CreateListView such that it can create anything of type TMyType, define the generic method like this:
private TMyType Create<TMyType>()
{
TMyType createdObject = new TMyType();
int count2 = autolayoutGroups.Controls
.OfType<TMyType>()
.Count();
createdObject.Size = new System.Drawing.Size(150, 100);
createdObject.BackColor = normalColor;
createdObject.BorderStyle = BorderStyle.Fixed3D;
createdObject.ForeColor = System.Drawing.Color.Black;
createdObject.Name = "Group" + count2;
createdObject.MouseDown += Select;
return createdObject ;
}
So all I did was, that whenever I save ListView, I replaced it with TMyType, the type that should be created.
Usage:
ListView createdListView = this.Create<ListView>();
DataGridView createdDataGridView = this.Create<DataGridView>();
ComboBox createdComboBox = this.Create<ComboBox>();
There is only one problem. You'll have to tell the compiler that TMyType has a default constructor (you want to do new TMyControl()), and that is has methods like Size, BackColor, ForeColor, etc.
If TMyType would be a class derived from Control, then you would be certain that it has the desired constructor and knows all methods that you need to use.
To say that a generic type is derived from a certain type, you use the following structure:
private TMyType Create<TMyType>() where TMyType: Control
{
// because you are certain the TMyType is derived from Control
// you can use all methods of class Control
}
This answers your question: create a generic method
Some other things about generics
Another example: If you want to inform the compiler that the generic type implements IComparable:
private T Process<T>(T input) where T: IComparable {...}
Or multiple:
private T Process<T>(T input) where T: IComparable, IEquatable {...}
And finally if you want to require that the generic type has a default constructor:
private T Process<T> () where T: new
It's not really clear what the goal is but I suppose you can make a property that returns your commonly used list:
private List<ListView> AutolayoutGroupControls =>
autolayoutGroups.Controls.OfType<ListView>().ToList()
Then you can
foreach(var lv in AutolayoutGroupControls)}
...
}
But it doesn't offer much; if you change that prop to return something else you still have a stack of changes to make. If your loops always do the same thing put it into a method and call it from N event handlers

Creating static Windows.Forms.Control

I have a project to which I delegate the function of creating a library of (static)? classes used in all my other projects. It is referenced via solution in these cases.
For instance, I have an extension which creates checkboxes within a given GroupBox's panel, and that works great:
public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
var count = 0;
listaCheckBoxs.ForEach(
i => {
i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
i.AutoSize = true;
count++;
});
p.Controls.AddRange(listaCheckBoxs.ToArray());
}}
Problem is, I need to insert a static checkbox on the top of the list, which will receive a method to (un)?check all the checkboxes below.
So my code will become
internal static CheckBox CKB_ancora = new CheckBox(){};
public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
var count = 0;
if (adicionaAncora) {
CKB_ancora.Text = textoAncora;
CKB_ancora.CheckedChanged += (sender, args) => {
ChecaCheckBoxes(p, CKB_ancora.Checked);
};
listaCheckBoxs.Insert(0, CKB_ancora);
}
listaCheckBoxs.ForEach(
i => {
i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
i.AutoSize = true;
count++;
});
p.Controls.AddRange(listaCheckBoxs.ToArray());
}}
where ChecaCheckBoxes is another
public static void ChecaCheckBoxes(this Panel b, bool checkStatus = true) {
var listaCheckBoxs = (from Control c in b.Controls where c is CheckBox select (CheckBox)c).ToList();
listaCheckBoxs.ForEach(
i => {
i.Checked = checkStatus;
});
}
and CKB_ancora needs to be a solution-wide recognized object.
The reason? I have another extension named GetSelectedCheckBoxes which will be used to return all the checked ... ah... checkboxes within the groupbox. And, in order to make sure that the "anchor" (I call it like this, since I don't have a name to a (un)?check-all checkbox) won't be returned as well.
If I run this code, it will compile, but... will run accross an InvalidOperationException at Application.SetCompatibleTextRenderingDefault, right at Main(); Apparently, a control cannot be created/instantied before this method is run at mainpoint, which is the exact definition of "static".
Question: Knowing that I NEED a way to keep this particular check solution-wide visible... How do I do it?
Unfortunately, you have not provided a good, minimal, complete code example, and lacking enough context it is very hard to provide good, specific advice.
That said, it seems that somewhere in this static class of yours, you have a field named CKB_ancora, and you are probably initializing it using a field initializer, possibly like this:
private CheckBox CKB_ancora = new Checkbox();
And having done this, you are finding that when the class is initialized (typically on the first time something in the class is accessed at runtime), that happens too soon and an exception is thrown.
Assuming that's correct, then it seems to me that most obvious and simplest "fix" is to initialize the object lazily. For example:
private Lazy<CheckBox> _ckb_ancora =
new Lazy<CheckBox>(() => new CheckBox());
private CheckBox CKB_ancora { get { return _ckb_ancora.Value; } }
That will wrap the object storage in a property, which in turn uses an instance of Lazy<T> to defer initialization until the first time any code actually tries to access it.
Now, that said, I'm not very enamored of your approach here, with a static member that is used in some instantiated object. What if someone using your library wants to use the code with two or more Panel instances? A Control (including a CheckBox) can't be a child of more than one other Control at a time, so having a single static instance of the Control is just not going to work.
IMHO, it would probably be better to instead use some identifying feature such as the Name or Tag property of the CheckBox to handle the control appropriately (e.g. such as filtering it out of enumerations).
For example:
public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
var count = 0;
if (adicionaAncora) {
CheckBox CKB_ancora = new CheckBox();
CKB_ancora.Text = textoAncora;
CKB_ancora.Name = "CKB_ancora";
CKB_ancora.CheckedChanged += (sender, args) => {
ChecaCheckBoxes(p, CKB_ancora.Checked);
};
listaCheckBoxs.Insert(0, CKB_ancora);
}
listaCheckBoxs.ForEach(
i => {
i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
i.AutoSize = true;
count++;
});
p.Controls.AddRange(listaCheckBoxs.ToArray());
}}
And, for example:
public static void ChecaCheckBoxes(this Panel b, bool checkStatus = true) {
var listaCheckBoxs = b.Controls
.OfType<CheckBox>().Where(c => c.Name != "CKB_ancora").ToList();
listaCheckBoxs.ForEach(
i => {
i.Checked = checkStatus;
});
}
That way, when you go to retrieve the list of CheckBox controls, the special one you added at the beginning is ignored.
Even with that, I think the code is still pretty fragile. The above would work better, but IMHO it would probably be even better if you weren't using static members for all of this in the first place. I.e. instead you should design some mechanism that allows you to relate an instance of the helper class to the Panel object it's helping with, so that you can in fact initialize and store per-instance information, without running into problems of order of execution, as well as of limitations of use of the code with just a single client.
Without a better code example, I don't see any good way to offer any specific advice along those lines though.

FlyoutNavigation Controller

Using MonoDevelop, I have been looking at an IOS implementation of a side slide out menu using FlyoutNavigationController, but have hit a couple of stumbling blocks.
Firstly, how can you access the font elements of the generated list?
I can easily modify row heights etc, but am unsure of how to proceed with modifying the list items, can this be down with a tablesource and item styling?
Secondly, how to open a view from this list?
Currently an empty view is used by default but new views are to be opened from the side menu list, I have tried using the push navigation controller but it fails to open.
Any ideas are more than welcome.
navigation = new FlyoutNavigationController();
navigation.View.Frame = UIScreen.MainScreen.Bounds;
View.AddSubview(navigation.View);
navigation.NavigationRoot = new RootElement ("Menu List")
{
new Section ("Menu List")
{
from page in SlideList
select new StringElement (page.title) as Element
}
};
navigation.NavigationTableView.BackgroundColor = UIColor.DarkGray;
navigation.NavigationTableView.RowHeight = 30;
navigation.NavigationTableView.SeparatorStyle = UITableViewCellSeparatorStyle.SingleLine;
navigation.NavigationTableView.SeparatorColor = UIColor.LightGray;
navigation.NavigationTableView.SectionHeaderHeight = 60;
//navigation.NavigationTableView.DataSource = SlideList;
//navigation.ViewControllers = Array.ConvertAll (MenuItems, title => new UINavigationController (new TaskPageController (navigation, title)));
navigation.ViewControllers = Array.ConvertAll (MenuItems, title => new TaskPageController (navigation, title));
this.NavigationItem.LeftBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Action, delegate {
navigation.ToggleMenu();
});
I haven't used the FlyOutNavigationController before, but I took a look at this example:
https://github.com/xamarin/FlyOutNavigation
It looks like you're supposed to have the same number of StringElements as Controllers. For the ViewControllers array, it looks like you can supply your own custom controllers instead of just plain ViewControllers. After that, clicking a list item should automatically navigate to the appropriate controller.
In regards to styling, looking at the source for this NavigationController, I don't see much in terms of being able to stylize the cells. I did a quick search for how to go about styling MonoTouch Dialog lists and it looks like there isn't an easy way without subclassing elements:
Monotouch Dialog: Styling Elements
However, I can share with you how I've accomplished the two questions you asked without the Dialog framework.
You can create a custom class that extends UITableViewSource:
http://docs.xamarin.com/guides/ios/user_interface/tables/part_2_-_populating_a_table_with_data
In the GetCell method override, you can grab an instance of the cell's label and set the font like so:
cell.TextLabel.Font = UIFont.FromName("TitlingGothicFB Cond", 20);
Another thing you can do with your custom UITableViewSource class is create a custom event:
public event EventHandler ListItemSelected;
Inside the RowSelected method you can dispatch this event:
public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
ListItemSelected(this, new MyCustomEventArgs(indexPath.Row));
}
In the controller class that was responsible for instantiating this TableSource, you can listen and handle this event like so:
var customTableSource = new CustomTableSource(myList);
MyTable.Source = customTableSource;
customTableSource.ListItemSelected += (object sender, EventArgs e) => {
if((e as MyCustomEventArgs).rowSelected == 1){
this.NavigationController.PushViewController(new MyNextViewController(), true));
}
}

How to create a textbox which has same attributes as another textbox?

I need to create and add some TextBoxes which has same attribute as some other TextBoxes.
Is there a way to copy the attributes to another ?
I'm looking for a one like solution. I know I can set variable one by one.
TextBox Old = new TextBox() {
Size = new System.Drawing.Size(25,25),
Location = new Point(a.row*25, a.col*25),
Multiline = true
};
TextBox New = new TextBox(); //which has same location,size as old one ?
EDIT The TextBox might be any other .NET controls !
You can use this Solution. You can write a extention and that get via Reflection all propertys
Please use the search function in future.
Create an initializer method:
private void InitializeTextBox(TextBox textBox)
{
textBox.Size = new System.Drawing.Size(25, 25);
textBox.Location = new Point(a.row * 25, a.col * 25);
textBox.Multiline = true;
}
And use like this:
TextBox t1 = new TextBox(), t2 = new TextBox();
InitializeTextBox(t1);
InitializeTextBox(t2);
Or a copier method:
private void CopyTextBoxProps(TextBox source, TextBox dest)
{
dest.Size = source.Size;
dest.Location = source.Location;
dest.Multiline = source.Multiline;
//...
}
and use it accordingly.
Probably the most straightforward way is this:
TextBox New = new TextBox {
Size = Old.Size,
Location = Old.Location,
Multiline = Old.Multiline
};
If this is something you need to do a lot, you could write an extension method that does the same thing:
public static class TextBoxExtensions {
public static TextBox Copy(this TextBox textBoxToCopy) {
var copiedTextBox = new TextBox {
copiedTextBox = textBoxToCopy.Size,
copiedTextBox = textBoxToCopy.Location,
copiedTextBox = textBoxToCopy.Multiline
};
}
}
Usage:
var copyOfOld = Old.Copy();
If you are going to add a lot more properties to copy, I'd think about using AutoMapper and defining a map between TextBox and TextBox. If you're interested in that path, let me know and I'll post a sample.
It would turn this into a one liner, but you'd need a dependency on AutoMapper, but it's available on NuGet: http://nuget.org/packages/AutoMapper/2.2.0
First, take a dependency on AutoMapper.
Define the mapping somewhere in your project:
Mapper.CreateMap<TextBox, TextBox>();
Usage:
var newTextBox = Mapper.Map<TextBox, TextBox>(Old);
or, if you already have an instance you want to stuff it into:
Mapper.Map(Old, newTextBox);
AFAIK, there is no built in, one line solution, so it's either the extension method, or take a dependency on AutoMapper. The extension method does not have to do it that way, you can use reflection or other choices there.
I use AutoMapper in just about all of my projects and it's invaluable.
You can define many mappings in your map definition, then all your copies become one liners. Well, besides the definition :)

Dynamically Cast Page.LoadControl in C#

I'm writing some user controls for the first time and I'm wondering if there's a way I can clean up some of my code. (If you'd like more background on what I'm working on, see this question.)
I have a BaseControl class that, basically, parses some XML data and then, depending on what is contained in that data, calls the appropriate UserControl and sends the data on its way. Here's an example:
public partial class BaseControl : User Control
{
protected void Page_Load(object sender, EventArgs e)
{
... //code that parses the data
var renewalDef = effort.Attributes["renewal_def"].Value;
var effortNumber = effort.Attributes["renewal_effort_number"].Value;
if (effortNumber == "1")
{
var effortControl = (NAVLEffort1) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort1.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
if (effortNumber == "2")
{
var effortControl = (NAVLEffort2) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort2.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
if (effortNumber == "3")
{
var effortControl = (NAVLEffort3) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort3.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
// and so on...
}
}
This isn't the actual code I've written, it's just an example of where I could be headed. What I'd like to do is something more like this:
...
var effortControlFileString = string.Format("~/NAVLSeriesControls/{0}Effort{1}.ascx", renewalDef, effortNumber);
var effortControl = (renewalDef + "Effort" + effortNumber) Page.LoadControl(effortControlFileString);
effortControl.transactionData = transaction;
HtmlContent.Controls.Add(effortControl)
...
Any ideas how I can clean this mess up?
Interface
You could have all controls implement a common interface and cast to that.
public interface IMyInterface
{
object TransactionData
{
get;
set;
}
}
Control effortControl = Page.LoadControl(path);
HtmlContent.Controls.Add(effortControl);
IMyInterface obj = (IMyInterface)effortControl;
obj.TransactionData = transaction;
See this working example in an online IDE.
Base Class
You could also use an abstract base class and cast to that type with the same results. You will need to use a base class which inherits from UserControl. This would avoid having two object references (as in my example above) because it can be cast to UserControl.
The example above becomes:
MyCustomControlType c = (MyCustomControlType)Page.LoadControl(path);
HtmlContent.Controls.Add(c);
c.TransactionData = transaction;
If the logic for each control type is different, then you will probably need to cast to each specific type (basically a big if/else block) and deal with each control individually. In other words, if you need to perform different actions based on the type of the control, you will need logic that is type-aware.
For completeness sake I will mention that you could also use the DLR but I would suggest against it. You would be giving up compile-time type safety and performance to reduce a little code.
you can create an interface and add your control to html page.
ex:
private Control _contentControl;
_contentControl = Page.LoadControl("~/Administration/Projects/UserControls/" + controlName);
((IEditProjectControl)_contentControl).ProjectId = ProjectId;
plhContent.Controls.Clear();
plhContent.Controls.Add( _contentControl );
_contentControl.ID = "ctlContent";
Image2.Visible = ((IEditProjectControl)_contentControl).ShowSaveButton;
SaveButton.Visible = ((IEditProjectControl)_contentControl).ShowSaveButton;
((IEditProjectControl)_contentControl).Initialize();

Categories

Resources