I'm building some web user controls and just wondering what is the right / best practice approach to implement properties. In this example he control is a "score card" control which has to display a score ( and it also has to do other stuff) ....to make things easier I made these code samples very simple but in reality my control does other stuff as well with the score besides displaying it in a label :-)
Choice #1
private int _score;
public int Score
{
get { return _score; }
set { _score = value; Refresh(); }
}
public void Refresh()
{
lblScore.Text = Score;
}
Choice #2:
public int Score {get;set;}
protected void PageLoad(object sender, EventArgs e)
{
Refresh();
}
private void Refresh()
{
lblScore.Text = Score;
}
Choice #3:
public int Score
{
get { lblScore.Text; }
set { lblScore.Text = value; }
}
So , of course, the question is what is the best practice way of implementing the Score property of the control ....:-)
MadSeb
Choice 1
Choice 2 is out of this because you should not link initialization and functionality to specific page events in a UserControl. That is a source for nasty errors related to Page-Lifecycle. You might want to make modifications after Page_Load(f.e. in a Button's Click-Event in the page) but it's too late for the implicit Refresh.
Choice 3 is out because for simply setting the Text of a Label you don't want somebody to remember that he has to call Refresh after he has set the Score. But that depends on how expensive "my control does other stuff as well with the score besides displaying it in a label" is. If you often change the Score but not necessarily need to refresh immediately, i would do the Refresh after all initialization has done.
In my opinion a UserControl should encapsulate complexity as long as it keeps enough flexibility and control to be reusable. Don't do too much "magic" things in the background that might cause errors in different conditions that you won't find quickly. That is particularly so in a Setter what normally only should set the corresponding variable.
There are two different use cases for an UserControl:
Reusability.
If your control contains only few controls but you want to reuse it many times, i would let the controller get/set properties and don't do complex things in it that depend on specific conditions. That would reduce reusability. You might want to provide clear methods and events that the controller could handle.
Container.
If your control behaves similar to a page and has a lot of controls and functionality, it should do most of all by itself. You only want to provide a few methods and events(that don't have to be handled necessarily). The most important method in this case would be e.g. a public void BindData() that does all initialization after the controller has set the necessary variables. That is the replacement for your Choice 2.
Note: if your score is stored in lblScore.Text as string anyway, i would prefer using the Text property of the label instead of creating another int-variable(cast it to an int in the getter). That has the advantages that you don't need to store your variable in ViewState manually, because it's already stored. On this way you don't need to set it on every postback.
Related
I am building a simple journal form based on the form pattern DetailsTransaction. In this pattern it has the standard two view layout, the header/*journalTable grid and a lines/*journalTrans grid.
However, when I click the New button two create a new header/journal, it automatically invokes the taskSwitchToDetailsView task and switches to the lines. I wish to block this from happening, but I am unsure on how to do it. Is there a way to block this task from being invoked?
Have you experimented with the viewEditModeHelper() and other form event handlers?
I don't have an environment in front of me now, but here's a little snip that might give you an idea where to look. I know it's not exactly what you're looking for but the same style is what I would think.
[FormEventHandler(formStr(LogisticsPostalAddress), FormEventType::Initialized)]
public static void MyForm_OnInitialized(xFormRun sender, FormEventArgs e)
{
// Subscribe event handlers
FormRun formRun = sender as FormRun;
formRun.viewEditModeHelper().EditModeSwitched += eventhandler(MyEventHandler.ViewEditModeSwitched);
}
There is a lot of complexity around the OOTB journals, and if I needed a robust journal implementation I would have created classes that derived from JournalFormController and JournalFormTable/JournalFormTrans which provide number sequence generation, blocking/locking, validation, and much more very useful and powerful functionality to a journal form + table structure.
However, I don't need any of that. So to solve my specific problem I added this to the create method of the *journalTable datasource's create method (which the super call changes the context of the form to the lines by calling task(#taskSwitchToDetailsView). To counter this, I simply call task(#taskSwitchToGridView) immediately after the super.
[DataSource]
class CustomJournalTable
{
public void create(boolean _append = false)
{
#Task
super(_append);
element.task(#taskSwitchToGridView);
}
}
I've created a lookup with two columns, first one containing and integer which works just fine but the second one has a long name and this is where the problem arises. Users should horizontally scroll in order to check the entire string and even in that case, the column's width is not big enough to display the whole data.
I've found this :
Adjusting column width on form control lookup
But i don't understand exactly where and what to add.
I am not sure but maybe I have to add the fact that this lookup is used on a menu item which points to an SSRS report, in the parameters section.
Update 1:
I got it working with a lookup form called like this :
Args args;
FormRun formRun;
;
args = new Args();
args.name(formstr(LookupOMOperatingUnit));
args.caller(_control);
formRun = classfactory.formRunClass(args);
formRun.init();
_control.performFormLookup(formRun);
and in the init method of this form i added:
public void init()
{
super();
element.selectMode(OMOperatingUnit_OMOperatingUnitNumber);
}
meaning the field i really need.
I am not sure i understand the mechanism completely but it seems it knows how to return this exact field to the DialogField from where it really started.
In order to make it look like a lookup, i have kept the style of the Design as Auto but changed the WindowType to Popup, HideToolBar to Yes and Frame to Border.
Probably the best route is do a custom lookup and change the extended data type of the key field to reflect that. In this way the change is reflected in all places. See form FiscalCalendarYearLookup and EDT FiscalYearName as an example of that.
If you only need to change a single place, the easy option is to override performFormLookup on the calling form. You should also override the DisplayLength property of the extended data type of the long field.
public void performFormLookup(FormRun _form, FormStringControl _formControl)
{
FormGridControl grid = _form.control(_form.controlId('grid'));
grid.autoSizeColumns(false);
super(_form,_formControl);
}
This will not help you unless you have a form, which may not be the case in this report scenario.
Starting in AX 2009 the kernel by default auto-updates the control sizes based on actual record content. This was a cause of much frustration as the sizes was small when there was no records and these sizes were saved! Also the performance of the auto-update was initially bad in some situations. As an afterthought the grid control autoSizeColumns method was provided but it was unfortunately never exposed as a property.
you can extends the sysTableLookup class and override the buildFromGridDesign method to set the grid control width.
protected void buildFormGridDesign(FormBuildGridControl _formBuildGridControl)
{
if (gridWidth > 0)
{
_formBuildGridControl.allowEdit(true);
_formBuildGridControl.showRowLabels(false);
_formBuildGridControl.widthMode(2);
_formBuildGridControl.width(gridWidth);
}
else
{
super(_formBuildGridControl);
}
}
I am very confused with properties in asp.net.
I just don't understand why we use properties and when I should use them. Could anybody elaborate a little on this.
public class Customer
{
private int m_id = -1;
public int ID
{
set
{
m_id = value;
}
}
private string m_name = string.Empty;
public string Name
{
set
{
m_name = value;
}
}
public void DisplayCustomerData()
{
Console.WriteLine("ID: {0}, Name: {1}", m_id, m_name);
}
}
Properties provide the opportunity to protect a field in a class by reading and writing to it through the property. In other languages, this is often accomplished by programs implementing specialized getter and setter methods. C# properties enable this type of protection while also letting you access the property just like it was a field.
Another benefit of properties over fields is that you can change their internal implementation over time. With a public field, the underlying data type must always be the same because calling code depends on the field being the same. However, with a property, you can change the implementation. For example, if a customer has an ID that is originally stored as an int, you might have a requirements change that made you perform a validation to ensure that calling code could never set the ID to a negative value. If it was a field, you would never be able to do this, but a property allows you to make such a change without breaking code. Now, lets see how to use properties.
Taken From CSharp-Station
There are a couple of good reasons for it. The first is that you might need to add validation logic in your setter, or actually calculate the value in the getter.
Another reason is something to do with the IL code generated. If you are working on a large project that is spread over multiple assemblies then you can change the code behind your property without the application that uses your assembly having to recompile. This is because the "access point" of the property stays the same while allowing the implementation code behind it to be altered. I first read about this when I was looking into the point of automatic properties as I didnt see the point between those and a normal public variable.
It's easy.
All fields in class MUST be private (or protected). To show fields to another class yyou can use properties or get/set methods. Properties a shorter.
P.S. Don't declare write-only properties. It is worst practices.
Properties are a convenient way to encapsulate your classes' data.
Quoting from MSDN:
A property is a member that provides a flexible mechanism to read,
write, or compute the value of a private field. Properties can be used
as if they are public data members, but they are actually special
methods called accessors. This enables data to be accessed easily and
still helps promote the safety and flexibility of methods.
Let's consider two common scenarios:
1) You want to expose the Name property without making it changeable from outside the class:
private string m_name = string.Empty;
public string Name
{
get
{
return m_name;
}
}
2) You want to perform some checks, or run some code every time the data is accessed or set:
private string m_name = string.Empty;
public string Name
{
get
{
return m_name;
}
set
{
m_name = (String.IsNullOrEmpty(value)) ? "DefaultName" : value;
}
}
see:
http://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx
The most important reason is for validation purpose in setter and manipulation part can be implemented in get part.
For Ex.
Storing weekdays, which should be from 1-7, if we take normal variable and declare it as public, anyone can assign any value.
But in Properties setter you can control and validate.
The next one you can use it for tracking. That means, you can know how many times set and get functions has been called by clients (statistical purpose, may be not useful frequently).
Finally, you can control read only, write only and read/write for the properties according to your requirements.
I have a simple page with a Grid that I'm binding a collection of objects to. I also have some simple functionality on the grid to edit and save rows. I would like to write unit tests for this page, but it's not really making sense to me.
For example:
Private Sub LoadGrid()
'Populate Collection
grid.datasource = MyCollection
grid.databind()
end sub
I guess a Sub really doesn't need a unit test, but what if this were a function that returned true when the grid had been loaded. How do you write a unit test for this? What other test should be done on a simple web page like this?
As always, thanks to everyone who give any sort of input.
How do you write a unit test for this?
The first step is actually making your form testable. Have a look at this page for separating UI and BL layers, there are about a bajillion different ways to implement MVC, MVP, and all of its variants, and there's no One True Way™ to do it. So long as your code is sane and consistent, other people will be able to work on your code.
I personally find the following pattern works in most cases for testing UIs:
Create an interface representing your Model.
Create a class for your controller which handles all the updates to the model.
Your view should listen to changes to the model.
So in the end, you end up with something like this (sorry, my VB-fu is rusty, writing this in C# instead):
interface IProductPageModel
{
int CurrentPage { get; set; }
int ItemsPerPage { get; set; }
DataSet ProductDataSet { get; set; }
}
class ProductPageController
{
public readonly IProductPageModel Model;
public ProductPageController(IProductPageModel model)
{
this.Model = model;
}
public void NavigateTo(int page)
{
if (page <= 0)
throw new ArgumentOutOfRangeException("page should be greater than 0");
Model.CurrentPage = page;
Model.ProductDataSet = // some call to retrieve next page of data
}
// ...
}
This is concept code, of course, but you can see how its very easy to unit test. In principle, you could re-use the same controller code in for desktop apps, silverlight, etc since your controller doesn't depend directly on any particular view implementation.
And finally on your form side, you'd implement your page similar to:
public class ProductPage : Page, IProductPageModel
{
ProductPageController controller;
public ProductPage()
{
controller = new ProductPageController(this);
}
public DataSet ProductDataSet
{
get { return (DataSet)myGrid.DataSource; }
set { myGrid.DataSource = value; myGrid.DataBind(); }
}
protected void NavigateButton_OnCommand(object sender, CommandEventArgs e)
{
controller.NavigateTo(Convert.ToInt32(e.CommandArgument));
}
}
Here there's no real distinction between view and model -- they're the same entity. The idea is to make your code-behind as "stupid" as possible, so that as much testable business logic is contained in the controller as possible.
What other test should be done on a
simple webpage like this?
You'd want tests for any sort of form validation, you want to make sure you're throwing exceptions in exceptional cases, ensuring that your controller methods update your model in an expected way, and so on.
Juliet is right.
The line of code where you said
'Populate Collection
that is the testable part. You can do assertions on if the collection is null, if it has items, if it has exactly 42 items. But that would be an integration test.
If you can isolate all the calls to the database (the part that returns a datareader), then return a empty, fake DbDataReader, then you can test everything inbetween the UI and the database.
Tests that spin up a browser and verify that a table is render, similarly is a integration test that will depend on having IIS up and working (and a DB up and working, unless you have a repository you can fake)
If you are just getting started, I would look for all the easy to test code first, such as methods that do have dependencies on the database, then move on the tricker tests that require mocking/stubbing/faking database servers, etc.
I'm working on a CRUD site with a lot of very similar forms for adding new data. In other words:
AddMovie.aspx, AddGame.aspx, AddBeer.aspx, AddAdd.aspx
I keep thinking to myself, "Self, it would be really nice to have a single Add.aspx instead of re-writing so many similar pages - plus all those OOP nerds would think I'm cool since I'm re-using instead of copy/pasting!"
So assuming I'm on the right track, if I were to go with the single Add.aspx page, how could I represent all sets of fields for each object? I thought about a bunch of panels or divs that I could hide/show, but not sure I really like that solution. Is there a better way to do it or should I just give up and go back to the multiple bad ol' AddObject.aspx pages?
Also, this is a plain ol' (3.5) web forms app. No ASP.NET MVC goodness for this one, sadly. It seems like there should be such a trivial solution and that I'm just over-thinking things, but I can't come up with one and so I turn to Stack Overflow. :)
Maybe you should look at ASP.NET dynamic data or the subsonic project. Both allow to build CRUD-type website very fast because they support "scaffolding" (the edit pages are generated automatically based on your database model).
A better way would perhaps be to have a single page called Add.aspx and then based on the querystring you send it (i.e. Add.asps?type=game) you could customize the form and the logic for the particular type of object your are trying to work with.
Another option is to subclass Page, and then make your pages inherit from it, so you've got one place with all common functionality.
For example:
public abstract class BasePage<T> : System.Web.UI.Page
{
protected T GetObjectById(int objectId)
{
// return new T();
}
protected void SaveObject(T obj)
{
// Save object to DB here
}
protected void DeleteObjectById(int objectId)
{
// Delete object
}
protected abstract void PopulateUI(T obj);
protected override void OnLoad(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
int objectId = Convert.ToInt32(Request.QueryString.Get("id"));
T obj = GetObjectById(objectId);
PopulateUI(obj);
}
}
}
Your pages would then inherit from this:
public class AddGame : BasePage<Game>
{
protected override void PopulateUI(Game game)
{
// Populate the UI with game information
GameNameTextBox.Text = game.Name;
PublisherNameTextBox.Text = game.Publisher.Name;
// etc
}
}
This should make creating the pages much quicker and easier, and gives you a bit more control over how data is retrieved and saved.