I have quite a lot going on now so I haven't been working on this much but I did get around to implementing the basic window for the Calculator. I did it in almost exactly the same way as the Alarm Clock Sample. I created a file myapp.cs and put in a Main() method, added a startup event handler, and then copied the rest of the file from the original version like so:
public class app : Application
{
[STAThread]
public static void Main()
{
app wpfcalculator = new app();
wpfcalculator.Run();
}
app()
{
this.Startup += new StartupEventHandler(AppStartingUp);
}
void AppStartingUp(object sender, StartupEventArgs e)
{
Window1 mainWindow = new Window1();
mainWindow.Show();
}
}
Then, I created a file window1.cs to, at this point, write the corresponding C# code for the XAML:
<Window x:Class="WPFCalculator.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Calculator"
Height="400"
Width="600"
ResizeMode="CanMinimize"
Icon="AppIcon.ico"
TextInput="OnWindowKeyDown"
>
The difference this time being I created a method "InitializeThis()" which will contain all the translated XAML to correspond to "InitializeComponent()" which is normally used to parse XAML. So what I ended up with is:
void InitializeThis()
{
this.Title = "WPF Calculator";
this.Height = 400;
this.Width = 600;
this.ResizeMode = ResizeMode.CanMinimize;
Uri iconUri = new Uri("appicon.ico", UriKind.Relative);
this.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconUri);
this.TextInput += new System.Windows.Input.TextCompositionEventHandler(OnWindowKeyDown);
}
I think it's a good idea to take all that out of the constructor. The code will be much easier to follow.
I must be getting used to .NET after going through the Alarm Clock Sample because I didn't even blink when I wrote this.ResizeMode = ResizeMode.CanMinimize;--it just seemed right that "ResizeMode" must be set to a certain value which would be enumerated and encapsulated in the "ResizeMode" object/method [update: looks more like its overloaded to be both an Enum object and a Property] itself. I also had a feeling that something like wouldn't work so I looked up the Window.Icon Property. The example given there, however, assumes that the icon resource is compiled along with the application but I wanted to use an external file so I just used the same idea as the window image used in the Alarm Clock Sample. The TextInput event handler code wrote itself using Visual Studio but I understand it. this.Icon = "appicon.ico"
As for "OnWindowKeyDown", I simply copied it. I don't like to just copy and paste when I'm learning so I typed it out. Of course, I didn't want to rewrite the whole program in one go so I didn't copy method calls:
private void OnWindowKeyDown(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
string s = e.Text;
char c = (s.ToCharArray())[0];
e.Handled = true;
if ((c >= '0' && c <= '9') || c == '.' || c == '\b') // '\b' is backspace
{
return;
}
switch (c)
{
case '+':
break;
case '-':
break;
case '*':
break;
case '/':
break;
case '%':
break;
case '=':
break;
}
}
There's some interesting stuff there about C#, .NET, and programming practice.
As in the Alarm Clock Sample, event handlers need to accept certain arguments and, because C# is strongly typed, they need to accept very specific arguments. Here, an event object of type "System.Windows.Input.TextCompositionEventArgs" is accepted and that holds interesting information in its "Text" member. If any key is pressed we just want the first character of that key's associated sequence so that's what is copied into a variable and then we don't care about the event anymore so flag it as "handled". (I thought I read that strings can be indexed to retrieve characters so I tried changing the code to simply char c = e.Text[0]; and there was no problem compiling. I'm not sure why Microsoft wrote it differently but perhaps it's because of how unicode works.)
The use of "if" and "switch" blocks is the most fun part of this method. The keys which would be used to update the display (numerical, the decimal point, and backspace) are all handled similarly and they are used the most so they are checked simultaneously by the "if" statement before anything else. Note (c >= '0' && c <= '9') shows that characters can be ordered in C# (ASCII FTW).The operation characters are then checked by a "switch" statement. This makes sense because they each have a very different function, and it just looks better than "if (c == '+' || c == '-' || ... || c == '=')" especially if you're going to add more (key binded) operations later.
Next, I think I will check out "ProcessKey()" and however you get those keys to display.
No comments:
Post a Comment