Pages

Showing posts with label Tips. Show all posts
Showing posts with label Tips. Show all posts

Thursday, February 27, 2014

Disable auto complete on a form control

As a pattern, Dynamics AX has an auto complete feature in form controls.

There is a way to disable it though, programmatically.


There's the delAutoCompleteString method on the FormRun class. The name is pretty straight-forward.


We must override the control's textChange method to call it:

public void textChange()
{
    super();

    // Since we're overriding a control's method, "this" means the instance of the control.
    // We could also reference it by its name, if the AutoDeclaration property is Yes.
    element.delAutoCompleteString(this);
}


With that single line of code, we can disable the auto complete feature.

Thursday, February 6, 2014

Create implicit and explicit user-defined type converions in C#

I bet you had to write tons of static methods to convert between a user-defined type to another type, and that it always made your code very ugly and verbose, also creating lots of "helpers".

Well, C# has a nifty way to facilitate that for us.

Apart from using the keyword operator to overload default arithmetic operations, we can use it in conjunction with the implicit and explicit keywords to create new user-defined type conversions. One should already know the difference between explicit and implicit conversions.


Implying it


By defining a new operator using the implicit keyword, you can easily hide all of those static method calls, and write simple code, such as this:

var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

Bar bar = foo;

// Notice that we're not talking about polymorphism, 
// as there's no inheritance between the classes:
class Bar
{
    public string BarInfo { get; set; }
}

class Foo
{
    public int Size { get; set; }
    public string Name { get; set; }       
}

To do that, we simply defined a new implicit operator between the two types, such as:

public static implicit operator Bar(Foo foo)
{
    var bar = new Bar { BarInfo = string.Concat(foo.Size, " - ", foo.Name) };

    return bar;
}

The above code simply concatenates both properties of our Foo object and sets Bar's BarInfo property with the result.

MSDN says that the operator should be defined on the source type, although it works well if you define it on the target type. Also, it states that you should only use implicit conversions for user-defined types like this if you're absolutely sure that no exceptions may be thrown. If there's too much data transformation, and you may eventually get an exception, then it advises you to use explicit conversions instead.


Expliciting it

Let's say we have a Foo type, which already has an implicit conversion to a Bar type. But now there's this new BigFoo type for which we want to convert our Foo. A Foo needs to have a size of at least 10 to be considered a BigFoo. So what we want to do is:

var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

BigFoo bigFoo = (BigFoo)foo;

And to enable such code, we define an explicit operator between the two types on the Foo class:

class Foo
{
    public int Size { get; set; }
    public string Name { get; set; }       
        
    public static explicit operator BigFoo(Foo foo)
    {
        if (foo.Size < 10)
        {
            throw new InvalidCastException("Foo is not big enough to be a BigFoo!");
        }

        var bigFoo = new BigFoo { Name = foo.Name };

        return bigFoo;
    }
}
I'd rather read the above conversion code examples as they are then reading code that looks like this:
var foo = new Foo
{
    Size = 10,
    Name = "Foo"
};

var bigFoo = Foo.TryConvertToBigFoo(foo);
var bar = Foo.ConvertToBar(bar);

Monday, September 30, 2013

Any unnecessary code is evil code

I bet you have already gone through a situation where you added lines of code just because it was easy enough or because you were already changing something on the same part of the program.

Well, don't.



No matter how easy it is to do something, no matter how fast, if you don't have a real - and good - reason to do it, don't.

Here are some questions you can ask yourself before implementing something, some that I keep asking myself all the time:

  • Does this add value to the product?

    Good code or features are the one that add value to the product as a whole. Just because a feature was well developed and works well doesn't mean that it adds value to the product.
    A feature that adds value to the product is something that the users also see as a value. How many times did you see a feature being added to the backlog, implemented and shipped just because your manager thought it was good, but after being shipped it ended up not being used at all?


  • Do the users really need this feature?

    Even if it does add value to the product, it may add little value to it. So the question is: do we really want to implement it?
    For example, to perform something the users have to click 5 times. You have the chance to reduce that from 5 clicks, to 3 clicks. But none of your users have ever complained about this, none of them have ever said anything about having to click too much to perform something. Do you really have to spend time improving that?


If the answer to both of the questions above is no, we can consider not implementing it.

But if after that you still want to implement it, ask yourself these two other questions:

  • What is the impact of this change, for your daily work?

    Always be very aware that even the smallest time you will spend on a change - even debating it - could be spent on a different matter. Even if you don't implement something you'll have to spend some time debating and agreeing on not doing so, and this takes time. Always remember that the time you spend on any feature could be spent on any other feature, one that adds more value to the product.


  • What bugs can this change generate?

    This is also a very important question. This is, in fact, what this post is all about. Giving a short answer to it: you may introduce a bug with code that you didn't need to write in the first place! Let's consider the example of the clicks again. What if, by reducing the number of clicks the user has to perform to achieve something, the programmer forgets to initialize something? That is awful from the user's point of view. The users had some process working with 5 clicks, and all of a sudden it got short - but it also doesn't work anymore. And guess what? He didn't request this change.


If you got bad answers for these questions, you will almost certainly not implement it all. And it's actually OK. It's all about delivering what adds value to the product, really.

Unnecessary code also goes into your ALM process, meaning you will also have to test it, write unit tests for it, and maintain it. All of these tasks take time from the programmers that could be working on something that really adds up to the product. Do you see the size of the problem work you have created, for something that will have no good response from your user base?

And don't forget that the next person who maintains these evil lines of code will spend some time trying to understand, and possibly fixing a bug or a unit test that was failing. All of that work for code that shouldn't have been added in the first place.

As I've said before: if you don't absolutely have to write code for something, don't.

Wednesday, November 16, 2011

ASP.NET 4.0 has not been registered on the Web server.


ASP.NET 4.0 has not been registered on the Web server.
You need to manually configure your Web server for ASP.NET 4.0 in order for your site to run correctly.



If you ever come across this warning message when creating a new Web Application or configuring your Web Site to be hosted directly on IIS instead of Visual Studio's Development Server, simply run the regiis util, inside the correct Framework's version installation folder, with Administrator privileges, like this:




That should solve it.

I'm not sure but I think this happens when you install the .NET Framework before you install IIS. If it happens with other versions of the .NET Framework, you should simply switch its folder to the correct version.



Here's the text:
cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
aspnet_regiis -i

Friday, May 6, 2011

Filtering a DataGridView

Been reading a lot of people getting confused about how to develop a filter to a DataGridView.

The easiest way to do that is to apply the filter to a BindingSource object, which will then modify the DataGridView to display the filtered result in it.

So, here's my example form design:




The only property I've changed on the designer on the DataGridView and the BindingSource is their names.
That ComboBox will let us decide which column we want to filter, with the TextBox's value. That CheckBox will indicate whether the filter is active or not.

A very easy way to implement a Live Filter

We'll implement a live filter, meaning the data will be filtered as the user types, instantly. Now, this kind of filter is pretty good for small data, small collections. Imagine instantly filtering 30000 records...

For our live filter, we'll assign each key control's event to the same handler, this way we'll have to write less code, it'll be easier.

Our DataGridView will have two columns, so here we throw in some sample data, and configure the comboBoxColumns items using an anonymous type, all inside our form's Load event:

private void FormTestGrid_Load(object sender, EventArgs e)
{
    // This prepares our data source and our grid:

    DataTable dt = new DataTable();

    DataColumn colName = new DataColumn("Name");
    DataColumn colPrice = new DataColumn("Price");

    dt.Columns.Add(colName);
    dt.Columns.Add(colPrice);

    dt.Rows.Add("Bike", 150.00);
    dt.Rows.Add("Helmet", 59.99);
    dt.Rows.Add("Shoes", 90.99);
    dt.Rows.Add("Shirt", 30.00);
    dt.Rows.Add("Blouse", 75.00);
    dt.Rows.Add("Cap", 30.00);
    dt.Rows.Add("Pants", 50.00);
    dt.Rows.Add("Glasses", 15.00);

    bindingSource.DataSource = dt;

    dataGridView.DataSource = bindingSource;

    dataGridView.Columns.Add("colName", "Name");
    dataGridView.Columns.Add("colPrice", "Price");

    dataGridView.Columns["colName"].DataPropertyName = "Name";
    dataGridView.Columns["colPrice"].DataPropertyName = "Price";


    // And this prepares our ComboBox to enable us to select what column we want to filter:

    comboColumns.DataSource =
        new[]
        {
            new { Text = "Name", Value = "Name"},
            new { Text = "Price", Value = "Price"},
        };

    comboColumns.DisplayMember = "Text";
    comboColumns.ValueMember = "Value";
}


The above code fills a DataTable and tells the BindingSource that it's its DataSource, adds the Columns to our Grid and binds them to the correct data source columns.
It also adds the items that represent our columns to the ComboBox.


Now we declare the method that will receive every control's key events:

private void FilterAction(object sender, EventArgs e)
{
}


We set our events to that handler, inside our constructor (Could also be inside our Load event):

public FormTestGrid()
{
    InitializeComponent();

    comboColumns.SelectedValueChanged += new EventHandler(FilterAction);
    txtFilter.TextChanged += new EventHandler(FilterAction);
    chkFilter.CheckedChanged += new EventHandler(FilterAction);
}

The BindingSource component has a 'Filter' property which accepts SQL-Like Syntax constraints. For more information check the MSDN documentation on it.

And now we can write the method that will actually apply the filter, FilterAction.

private void FilterAction(object sender, EventArgs e)
{
    if (chkFilter.Checked)
    {
        bindingSource.Filter = string.Format("{0} like '%{1}%'", comboColumns.SelectedValue, txtFilter.Text);                
    }
    else
    {
        bindingSource.Filter = string.Empty;
    }
}


Notice that we use 'like' instead of '=' so that it doesn't have to be the exact same value to filter, but that's just for our example, you should decide what works better for you.


So this is it, just with those few lines of code, assigning three control's events to the same handler, we can implement our live filter to our Grid.

Monday, December 13, 2010

Are code generators good for you?

"Our product helps developers focus on solving business problems, not technical ones"

I bet you can find a similar sentence on the website of any code generator out there in the market.

Here are just two of the ones we've tested:

GeneXus:




XAF:









Every developer knows that there is pa
rt of every user-interactive system that is repetitive, and sometimes end up taking more time than the business logic itself. I'm talking about forms, tables, and everything made to keep data integrity between those two. In systems where there is a lot of data to deal with this becomes really annoying. You have to build the database tables manually, build forms manually, create validations, select, insert and update scripts, all the routines for the maintenance, and run extensive tests, because as we all know, there's a higher possibility of making mistakes when what you're doing is repetitive.

That's what these generators want to solve. If all that boring part is automated, all you have to deal with is business, right?

Partially. As you may have already calculated, these tools can't read your mind, and telling them what you want can sometimes get tricky. In an attempt to make the development process easier and easier, these tools often end up with something so different from regular manual development that learning how to use it properly may take longer than you expect. That's the case with GeneXus, which has its own philosophy, and even its own language.

There are a few items you might want to consider if you want to use code generators like those:

Learning Curve:

As Felipe has mentioned in a previous post, I've had a week-long GeneXus course last week. And we've taken the shortest one of three options (the longest takes one month!). How's that for something that was created to make the development process easier? I'm not criticizing the complexity of the tool, I'm warning those who think about changing their development methods and are considering using one of these tools for its speed and simplicity.

Code Quality:

This should be quite predictable, but some managers might misunderstand where generators are useful. Code generators don't generate beautiful maintainable code and don't generate 100% efficient code. The only advantage of it, is that you didn't need to put too much effort into it.

Reusability:

Another point where managers usually don't get the point. Since generated code isn't usually as good as a developer would write, it shouldn't be reused at all. If you can't find your ways to do something thought the generator, don't even consider editing the code because sometimes that would mean to abandon the generator, since what you change won't be translated back to the generator (unless in very specific cases).

Some programmers might not like it:

My instructor has mentioned that everywhere he does a demonstration, managers love it, and developers hate it. That was the case with me initially (and mildly to this day). Why wouldn't a developer like something that will take the boring part out of his work ? Because the price for that is to change the way they do the rest, and if developers are always growing better in their career, having to work with something too specific might sometimes mean to change their path and learn something that's not interesting for other employers.

Lastly, if you're aware of these points, and you're ok with some restrictions, this might be a good step to take. Be sure to choose a tool that is widely adopted, has a large community, and well documented.