Tuesday, June 7, 2011

Login and Main Forms

Many Windows Forms Developers are confused about a simple Use Case.

The use case is:
- User starts an application.
- Login Form appears.
- Application Exists if the user closes the Login Form.
- Upon successful login the Login Form closes and the Main Form of the application shows.
- Application Exists if the user closes the Main Form.

Many developers suggests complex implementations including deriving from the ApplicationContext and use the derived class in an overload to the Application.Run() method.
Examples of what have been discussed:
http://stackoverflow.com/questions/1629205/windows-forms-create-the-main-application-after-login-which-form-to-run
http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/73aeabe3-42db-4747-b3c7-9a5e4ea393ac/
http://www.codeproject.com/KB/cs/applicationcontextsplash.aspx

The implemntation can be much easier than this.
The ide is to open the Login Form as a modal dialog in the MainForm Load event.
And close the main form if the result was not OK.

Try this:

Here is the entry point (nothing done here):
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}

Login Form:
public partial class LoginForm : Form
{
private bool _authenticated = false;

private void _loginBtn_Click(object sender, EventArgs e)
{
if (AUTHENTICATION LOGIC)
{
_authenticated = true;
this.Close();
return;
}

MessageBox.Show("Login Failed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}

private void LoginForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (_authenticated)
this.DialogResult = DialogResult.OK;
else
this.DialogResult = DialogResult.Abort;
}
}

Main Form:
public partial class MainForm : Form
{
private void MainForm_Load(object sender, EventArgs e)
{
var loginForm = new LoginForm();
if (loginForm.ShowDialog() != DialogResult.OK)
{
this.Close();
}
}
}


That's it.

Monday, April 18, 2011

ASP.NET Menu RTL

The ASP.NET Menu (asp:menu) has inline styles that forces left foating. You can find this out by examining the source of any page which has asp:menu tag. I don't know why this is forced, but anyway for right-to-left languages, you might need to float the menu to the right side. Now if you used tried to use float:right in the CSS, it on't apply as the inline style will overrule. To overcome this you have to modify the CSS style to the following: float:right !important;The !important keyword denotes that this style should overrule the inline style.

You will need to do the same thing in the .menu ul li style.
To let the menu items to start from the right. Otherwise you will find the last menu item comes first.

Wednesday, April 6, 2011

WP7 Localization Explained

I believe you are going to create a new Windows Phone Application to follow me in this article.
I’ll assume you understand that everything that applies for a language, also applies for the language-Culture.
I.e. you can use “en” for English or “en-UK” for English and United Kingdom culture.
The language will affect the translation and what’s written in the resource files will be used for that sake, and the culture will affect the formats of date, currency…etc.

Step 1 – Add Resource Files:
Anyone who has brief experience with localization in .net, will guess the first step.
You have to add a Resource file for each language you need to use in your application.
You should have a file for the default language and others for each other language used, having the same name as the default language file but with a small extension using each language abbreviation.
Let’s say I’m going to support English (default) and Italian. Then I should end up having something like:

MyResources.resx
MyResources.it.resx

If it’s your first time to use a resource file, this is added from: Project (right click) => Add => New Item => (pick Resource File).
- Needless to say, when you fill the resource files, the Name of each resource should match, and only the value should reflect the translation.
- So say I’m going to have (Hello/Hello) & (Hello/Ciao) as the English & Italian (Name/Value)s.

Step 2 – Declare the Languages you support:
We should tell the application which languages we are supporting. Guess it’s not smart enough to figure this out by itself.
And for this you we’ll have to close the project/solution. Then open the project file in notepad, and add the supported languages (except the default one) in the supported cultures tag, using semi-colon as a separator, as follows:
<SupportedCultures>it;</SupportedCultures>You’ll also need to define the default language in case the user is using a language you don’t support, and thus the default language should be used then.
For that you need to go to the Project Properties => Application (Tab) => Assembly Information (button) => Set the (Neutral Language).

Step 3 – Use Resource-File in code behind:
Let’s see if this is going to work.
In the MainPage.xaml.cs, I’ll write the following in the CTor of the page.
PageTitle.Text = MyResources.Hello;
Step 4 – Test:
Now you can test this on a device, and it should display the “Ciao” if you went to the phone settings and set “Italiano” as the display language.
But the Emulator won’t let you change the “Display Language”, so if you want to test this in the Emulator, you will have to set the language-culture in code. (Just for testing).
So go the App.xaml.cs and write the following in CTor or in the Launching event handler.
Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("it");You may also add the following if you are testing the culture (format of dates, currencies…etc.)
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("it");** Don’t forget to remove these when you finish testing.
Now you should see the localization working. I hate to say it but that’s not the end of it.

(UPDATE)
Now you can change the display language in the emulator, all you have to do is to click on the: "tap here to accept changes and restart your phone." link, which appears when you select a different Display Language.
Still this might be consume more time than applying the change in code.


Step 5 – Access the Resource Files in XAML:
To use the resource files in XAML, you need to map them to a Static Resource, to able to bind to them.
Say you have a TextBlock as follows.
<TextBlock Name="textBlock1" Text="Hello">And instead of hardcoding the Text, we want to use the resource files. In other words we want to bind the Text property of the TextBlock to the appropriate key/property of the resource files.
We will go and define the generated Resource class as a static resource in the App.xaml, as follows:
<Application.Resources>
<local:MyResources xmlns:local ="clr-namespace:MyNamespace" x:Key="AnyGivenKey" />
</Application.Resources>
Please make sure you replace MyNamespace with the namespace under which MyResources is defined.
If you try to run the application now the following exception will blow right in your face:
AG_E_PARSER_UNKNOWN_TYPE [Line: 10 Position: 65]
Of type: System.Windows.Markup.XamlParseException
This issue has been reported here: http://connect.microsoft.com/VisualStudio/feedback/details/628281/silverlight-wp7-resource-files-and-binding

That’s because the class generated for the resource file was marked internal, and to access it from the XAML we need it to be public.
If you open each of the resx files, you will find an option in the toolbar to change the access modifier.
This should change the access modifier of the classes, but we still need to change the access modifier of the CTor. So you will have to open the default language resx.cs file, and look for the CTor and change the internal to public.

Now the application can run safely without weird exceptions.
And now it’s safe to go back to the TextBlock and change it to the following to use the Static Resource we just defined in the App.xaml:
<TextBlock Name="textBlock1" Text="{Binding Path=Hello, Source={StaticResource AnyGivenKey}}"/>That’s all? You wish…
The problem now is: whenever you add extra resources to the resource files, the resx.cs class is re-generated and the modifier of the CTor gets set back to internal. So if you are happy with manually changing it each time you add a new resource and build your application, then you are done.
If it’s cumbersome tedious thing to manage, then we need to find another solution.

Step 5.2 – Access the Resource Files in XAML:
To overcome this internal access modifier thing, we will create a class that wraps the generated resources class, and use that as our static resource in the App.xaml, as follows:
public class MyResourcesWrapper
{
public MyResourcesWrapper()
{
}

private static MyResources _myWrappedResources = new MyResources();

public MyResources MyWrappedResources { get { return _myWrappedResources; } }
}
And then our TextBlock should be changed to:
<TextBlock Name="textBlock1" Text="{Binding Path=MyWrappedResources.Hello, Source={StaticResource AnyGivenKey}}"/>You will need to modify the Resource definition in the App.xaml into the following:
<Application.Resources>
<local:MyResourcesWrapper xmlns:local ="clr-namespace:MyNamespace" x:Key="AnyGivenKey" />
</Application.Resources>

One extra step to go (if you need to localize the application bar).

Step 6 – Localizing the ApplicationBar:
The application bar is not growing out of the Silverlight, it’s a shell system tray.
So using the binding method in the xaml file won’t work.
We will have to add items to the application bar in the code behind and set the required localized text as we’ve done earlier in step 3.
e.g.
MainPage.xaml
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
MainPage.xaml.cs

ApplicationBar = new ApplicationBar();

var appBarButton = new ApplicationBarIconButton(new Uri("/Images/appbar_button1.png", UriKind.Relative));
appBarButton.Text = MyResources.Hello;
ApplicationBar.Buttons.Add(appBarButton);

var appBarMenuItem = new ApplicationBarMenuItem(MyResources.Hello);
ApplicationBar.MenuItems.Add(appBarMenuItem);

References:

How to: Build a Localized Application for Windows Phone:
http://msdn.microsoft.com/en-us/library/ff637520%28v=VS.92%29.aspx
CultureInfo Class:
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(VS.95).aspx
Extra link for the WP7 toolkit controls:
http://blogs.msdn.com/b/delay/archive/2010/12/20/quot-and-she-d-say-can-you-see-what-i-m-saying-quot-how-to-localize-a-windows-phone-7-application-that-uses-the-windows-phone-toolkit-into-different-languages.aspx

Tuesday, January 18, 2011

Stopping IIS 6 Caching

One issue that I faced when deploying an ASP.NET 3.5 web application on IIS 6 (Windows Server 2003), was that web-pages always showed old data.

For example a GridView didn't show inserted or updated data unless we refresh the page (F5). Or if we restart IIS (iisreset).

After some googling it was apparent that this is an IIS6 issue.
And every try to solve it by setting caching and expiration settings in IIS 6 failed.

The only solution we found working is to hardcode the following in Global.asax

protected void Application_EndRequest(Object sender, EventArgs e)
{
HttpContext.Current.Response.CacheControl = "no-cache";
}

WebForm_postbackOptions is undefined

Yesterday we were deploying an ASP.NET application on a Windows Server 2003 & IIS6.

And suddenly we stumbled acorss a script error on every page the error was:
"WebForm_postbackOptions is undefined" and it was complaining about Scriptresource.axd

It turned out to be the server clock (date in specific) was not correctly set.
It was set somewhere in the past. And so IIS felt something fishy was going on, as the assemblies required to be loaded have build dates in the future.

It took us quite some time to come to the core of this issue, having to go through many articles on the net, describing different causes and solutions to the same error.

We got the hint from Siderite blog. Thanks be to him :)

Sunday, November 7, 2010

Parser Error

I was deploying an ASP.NET application on IIS 5.1 the other day, when I was hit by the following error when trying to access some of the aspx pages from the browser.

/*********************************************************************************/

Server Error in '/' Application.
--------------------------------------------------------------------------------
Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Only Content controls are allowed directly in a content page that contains Content controls.


Source Error:
Line x: [/asp:content]

Line x+1:

/*********************************************************************************/

All pages were content pages of some master page. And nothing was written after the closing content tag.

At first I thought this was some kind of .NET vs IIS version mismatch or that I needed to change some IIS settings, since this was running fine on different IIS versions.

But to my surprise, some pages were displayed fine.

After banging my head few times, I found out the cause. The pages that were complaining had some spaces and empty lines after the closing content tag. This should mean nothing in html, but I guess IIS 5.1 didn't like these.

Clearing everything so that the closing content tag is practically the last thing written in a page, did the trick.

Hope this becomes helpful to anyone facing the same issue.