Microsoft Research has a new cool and helpful application that writes music to a melody. Just sing, and Songsmith writes the music – the commersial is sort of corny. What happens if you run well known songs through Songsmith?
Denna händelse skulle kunna beskrivas i flera spaltmeter av text, innehållande detaljerade beskrivningar på hur jag letar efter var man ska klicka, om hur jag tror att allt har hängt sig, o.s.v… Till slut lyckades jag ladda upp detta gamla nummer på YouTube! Hoppas att det kan bli mer snart! Apart
Dagens ros går till Staffan för att han hjälpte mig med att ta fram en ny layout till evolutionsteori.se!
I have added a new textbox control to the .NET Controls section. The textbox is an extension of the RichTextBox control with regex based syntax highlighting.
Med eller utan The Pirate Bay eller torrents, kan man enkelt och snabbt ladda hem upphovsrättsskyddad musik. Nu drar rättegången mot The Pirate Bay igång, och fälls de, så borde de få konsekvenser även för Google. Låt säga att jag vill ladda hem Radio ga-ga av Queen.
Jag börjar med att surfa till Google och knappar in detta i sökrutan:
Med detta säger jag att jag vill filtrera bort de vanligaste dokumenten, att det är ett musikarkiv jag vill söka i, att det ska vara musik, och att ordet “queen” ska förekomma i resultatet.
Första träffen ger mig en katalog med musik av Queen. Jag klickar på den.
Nu ser jag en grön och fin sida, där just Radio ga-ga ligger överst. Jag klickar på den.
Ett litet popup-fönster med reklam visas. Underst i det lilla fönstret finns en länk med texten “download”. Ljuv musik…
Ladda inte hem upphovsrättsskyddat material, men fundera gärna på upphovsrättens kompatibilitet med Internet. Det där med att både ha och äta kakan…
The bytes of a file are the file’s data at the lowest level available, and in .NET bytes are usually stored in byte arrays. If you’re not trying to cheat in a role playing game by hacking some save file, why would you want to load the bytes of the file? You might want to pass the file something. Add it as an attachment in a mail or add it as a value in a database. In these cases, you are not bothered by the fact that the file is quite useless when stored in a byte array, in fact, you want the file as it is and you are not concerned by the issue that you can’t use the file’s format to access the actual data of the file.
Once the file is in a byte array, you can pass it to a SqlCommand object, convert it to a string, pass it to a web service, or indeed write it to disk.
To do this, create a FileInfo object to represent the file, and call the OpenRead method of the FileInfo object. OpenRead returns a FileStream object.
Dim Fi As New System.IO.FileInfo(“C:\Windows\notepad.exe”)
Dim S As System.IO.FileStream = Fi.OpenRead()
You can read the length of the file (in bytes) from the FileInfo object or the FileStream object. Either way, it is returned as a Long (64 bit integer), so it has to be converted to an Integer (32 bit). The largest amount of memory you can allocate is two gigabytes (Integer.MaxValue). Also, in Visual Basic (unlike C#) you need to know the last index, not the size of, when you declare an array. Therefore, if you want an array with 3 elements, use Dim MyArray(2) As MyType.
Dim X(CType(S.Length – 1, Integer)) As Byte
Then, call the Read method of the FileStream. Pass in the buffer (in this case X), the offset and the number of bytes you want to read.
S.Read(X, 0, CType(S.Length, Integer))
Close and dispose the stream, and you are done!
S.Close()
S.Dispose()
Now, do what you want with the bytes of the file. You might want to remember the file ending of the original file. That can be good to know if you want to write the file back to disk.
Delegates can point to both anonymous functions (mostly refered to as anonymous methods) and regular functions. To instantiate a delegate that will point at a regular function, just use the AddressOf operator followed by the function you want to use the delegate for. This could be the delegate declaration:
Public Delegate Function MyDelegateType(ByVal T1 As Integer, ByVal T2 As Integer) As Integer
Imagine a function that adds two numbers. This could be the code that instantiates the delegate:
Dim X As New MyDelegateType(AddressOf Me.Sum)
And not, when the Invoke method of X is called, the Sum method gets executed.
The delegate knows what to do because a reference to a function is passed to it when it is created. The AddressOf operator is used for that. You could pass some Visual Basic code to the constructor instead of a reference to a function. To do this, use the Function keyword instead. Imagine a delegate declaration called DelegateNoParameters, that takes no parameters, and has no return value. This is how I can instantiate it, passing a function created on the fly to the constructor:
Dim X As New DelegateNoParameters(Function() MessageBox.Show(“Hello!”))
Now, whenever you call the Invoke method of X, a message box will be shown.
To take this one step further, this is how I could use an anonymous function with the delegate declaration that required two parameters and one return value (MyDelegateType):
Dim X As New MyDelegateType(Function(A As Integer, B As Integer) A + B)
Note that the keyword Return isn’t used. Also note that currently, anonymous functions can only contain one single statement in Visual Basic. That of course means lots of limitations, but this feature opens up some possibilities that otherwise would have been unavailable, like Lambda.
Det händer inte ofta, men denna helg har jag varit barnfri. Jag utnyttjade den tiden till att ligga i soffan och se samtliga avsnitt av The Office, vilket tog sex timmar. Så kunde en normal dag se ut för 15 år sedan, innan man hade barn. Jag lyckades även göra en uppgradering av PhotoName i morse. Jag är själv igång att organisera och säkerhetskopiera gamla bilder, så jag sitter och väger på vilka funktioner man ska bygga in i programmet; det finns massor som skulle vara värdefullt. Men grundtanken, att lyfta ut fotodatum till filnamnet för att konsekvent bevara bildernas kronologi, är det viktigaste.
Here are the improvements made to the PhotoName tool in Januari 2009:
The folder browser remembers the last working folder. This is likely to reduce the time it takes to find the folder you want to work with.
Since the images are loaded, thumbnail and EXIF information is cached for fast preview and reaccess.
You can cancel the process of loading images and reading EXIF data. This is useful if the program is busy with loading data from a folder different from the one you are interested in.
For download and more information, see the Programs page.
Good or bad, here are some attributes of the PowerShell type system:
Variables are declared when they are first used. Just assign a value to a variable, and the variable is created if it doesn’t exist. The variables are not type safe. Try typing $x=10 followed by $x=”Hello” and you will see that $x is happy to change type for you, without complaining. However, by specifying the type before the name of the variable, you cannot assign a value of a different type without specifying the new type.
Start by assigning an integer value to a variable, and specify the variable type in front of the variable name.
[int]$i=10
If you try to assign a different integer value to the variable $i, PowerShell will accept it.
$i=20
But if you try to assign a string value to $i, it will not work because $i only accept integer values.
$i=”Hello” #Will not work
Whenever you like, you can change the type of a variable, by specifying a new type in front of it.
[string]$i=”Hello” #Works fine – the type of $i is changed
Names are not case sensitive, so this rather poor formatted iteration will run:
FOR($x=0;$x -lt 10;$X++) { Write-Host $x }
Notice that For and FOR is the same thing, that $x and $X is the same variable, and that the curly brackets are required, even though there is only one statement that is iterated here.
I have written a small program that renames image files in a fashion that they will be sorted in a chronological order by photo date when they are sorted on the filename. To do this, I had to extract the EXIF information to be able to read the photo date. Michal Altair Valasek has written an open source class, ExifWorks, in Visual Basic that does this. To use the class, pass a photo to its constructor, and then use properties access the EXIF data. At The Code Project you can read more about the class, and registered users can download it. The PhotoName application can be downloaded here.
Some things that can be accomplished using optional arguments can also be accomplished using overloading. I usually write the function with the most arguments first, and then I do overloaded versions of the function that calls the first version and provide the arguments like this:
Public Sub DoSome(ByVal X As Integer)
Console.WriteLine(X)
End Sub
Public Sub DoSome()
DoSome(4)
End Sub
This can also be accomplished using optional parameters. They are declared using the keyword optional. You also need to provide a default value to the optional argument like this:
Public Sub DoSome(Optional ByVal X As Integer = 4)
Console.WriteLine(X)
End Sub
This last example will effectively be the same for the one that calls the function, who still can call DoSome with one or no parameters. One syntax limitation is that all parameters declared after an optional parameter must also be optional.
As long as the procedure doesn’t contain any parameter arrays, it can be called using named arguments. In this example, the procedure HitMe can be called without named arguments like this: HitMe(1, 2) or using named arguments like this: HitMe(X:=1, Y:=2).
Public Sub HitMe(ByVal X As Integer, ByVal Y As Integer)
The code for calling a function that takes lots of optional arguments without using named arguments is really ugly. It might look something like this:
At PDC2008, Microsoft gave some information about the future of Visual Studio and C#. In 2010, C# and the .NET Framework will be in version 4 and Visual Studio and Visual Basic .NET will be in version 10. For those of you that wasn’t as lucky as mr. Alsing to actually be there, the speeches are available online at http://www.microsoftpdc.com/.
Some of the highlights: Anders Hejlsberg is talking about the future of C# and the game developer Frank Savage talks about XNA Game Studio and the XNA Framework.
To install Microsoft PowerShell version 1.0, you must download the correct package for your version of Windows from Microsoft Download Center. Some of the packages require that you validate your copy of Windows.
To see the complete list, search for powershell at Microsoft Download Center. Version 1.o is based on .NET Framework 2.0, so that (or a later version) must be installed. Version 2 can be downloaded here, and the current version (3.5) can be downloaded here.
You can switch to fullscreen by pressing Alt+Enter, but some of the newer graphic cards does not support the mode that it changes to. PowerShell checks this before changing the mode, so nothing bad will happen if you try this.
Allow for scripting
To check if scripting is activated in PowerShell, type:
Get-ExecutionPolicy
PowerShell should say Unrestricted, but if it says Restricted, your scripts will not be executed. To change this, type:
Detta var en hektisk vecka på jobbet. Den utlovade lågkonjunkturen som går jag fortfarande och väntar på. Min avdelning på jobbet spelade lite curling och tog ett par öl efter jobbet igår, och vem är jag att inte knäppa lite med mobiltelefonen?
Visual Studio 10 and .NET Framework 4.0 is under development and will arrive in 2010. The technology preview is available (VS 10 on a Windows 7 image) and some documentation is also already available. One new cool feature is MGrammar, a grammar modeling language for constructing language syntaxes, a bit like the good old Gold Parser written in VB6.
Microsoft has an introduction to MGrammar on MSDN, and my friend Roger Alsing quickly made a .NET language, Mg Basic, using MGrammar. Check it out!
In some of my applications, I make use of the MSScriptControl to execute dynamically generated scripts, or just to enable scripting in my applications. Windows Vista users will get an error if they install applications that use MSScriptControl, because it is not included in Vista by default, and since it’s a file that is controlled by the operating system, you should not include it in your MSI package. If the MSScriptControl is missing, you can get it from Microsoft Download Center. This is the direct link:
These options can also be set for all modules in the project settings window, or for each file in code. If the settings are in conflict, the setting written in code overrides the project setting.
Option compare
This option simply tells if strings will be compared case sensitive (option compare text) or binary (option compare binary). So, given that option compare is set to binary, A is set to False, otherwise True.
Dim A As Boolean = (“ABC” = “abc”)
Option infer
This option can be on or off. When infer is set to on, you do not have to type out the data type of a variable when you are declaring it.
This code will make A an Integer, since it is initialized with a integer value, and B a Short, since it is initialized with a short integer value.
Dim A = 1
Dim B = 2S
When option infer is set to off, you must type out the name of the datatype. Either way, the code is still type safe.
Compile options can be set for all source code files at the same time in the project file, and they can be overridden in each file. If you want to override a compile option for file, just make sure that the compile option(s) are the first line(s) in the file, before any code. The compile options are option explicit, option strict, option compare and option infer. This post covers option explicit and option strict.
Option explicit
This option can be on or off, and choosing anything but on is just silly. When option explicit is set to on, all variables have to be explicitly declared. Imagine a function with these two lines:
X = 10
Console.WriteLine(X)
This will only compile if option explicit is set to off. And this is just stupid. All variables will be declared automatically at the first time they are referred to, and mistakes that normally would be caught by the compiler (like a misspell or a value assign of the wrong type) will be accepted by the compiler.
Option strict
This option can be on or off, and you should have a really good reason for choosing anything but on. This has to do with type casting. When option strict is set to off, you can do implisive casting any way you like, just as long as the value fits in the destination variable. If you have the number five stored in a 32 bit integer variable, you can assign it to a 16 bit integer. It’s the same way with objects. You can assign an object to a less specific variable and back to a more specific. You will get a runtime exception if the target type is not suitable. When option strict is set to on, you can only assign values from more specific to less specific variables, without using explicit type casting. This will work independent on option strict:
Dim X As Short = 10
Dim Y As Integer = X
This requires that option strict is set to off:
Dim I As Integer = 4
Dim S As Short = I
And if you want to do the last operation and you are working with option strict set to on, you can do an explicit cast of the type:
Dim I As Integer = 4
Dim S As Short = CType(I, Short)
In a way, working with option strict set to on is good, because that means that you have to prove that the code you’re writing is what you intend to do. That you have to actually do the cast, means that you know that you are doing something that (depending on the value of I) might fail.
It is very easy to present data on a web page using Visual Studio. I want to give a suggestion on how to present a substitute for a value. For this example, I use Visual Studio 2005 and SQL Server 2005.
Imagine a database (TestDatabase) with a table. One of the columns in the table is a Short (smallint in SQL Server) called Answer. If the value of that column is 0, you want to present the value “No answer”, if the value is 1, you want to present the value “Yes”. Finally, if the value is 2 you want to present the value “No”.
Let’s start with the problem. To display data from the table, I could create a data source on a web page, and connect it to a GridView control. Perhaps it’s even more easy to just drag a GridView control to the web page, and use the wizard to create a data source. The wizard can be accessed by selecting “New data source” as a the datasource in the task pane of the GridView control. After completing the wizard, the GridView now shows the content of the underlying table. It shows the actual values of the Answer column, that is 0, 1 or 2 instead of “No answer”, “Yes” or “No”.
This is one solution for the problem: Templates!
To convert the Answer column of the GridView to a TemplateField, open the task pane for the GridView control again. It looks different now when the control is connected to a data source. Click Edit Columns to bring up the Fields dialog, in the Selected fields list, highlight the Answer column and click the link labeled “Convert this field into a TemplateField”.
…and it can no longer be edited using the Fields dialog. How ever, you can now replace the label in the <ItemTemplate> tag with any control you like, a custom one if you like. Now, all you have to do, is to assign the value of the field to the desired property of a custom web control that you have created. And that control can write any replacement value to the result stream depending on the value of the property that is assigned to the control.
This might be the HTML code in <ItemTemplate> tag:
If you use Microsoft Reporting, anyone that is used to work with ASP.NET 2.0 or later will be very familiar. In this example, I use the Northwind database (Microsoft Access – not SQL Server). Add the report file, create and configure the data source using the built in wizard, drag fields from the Data Sources window onto the report, and finally, if required, modify the typed dataset that the wizard supplied to you. To view a Microsoft Reporting report, use the Report Viewer control in the Data section of the toolbox.
In detail, open the typed dataset. Right click on the data table and click Configure. You should see a query looking something like this:
To add a parameter, append the following code to the query:
WHERE EmployeeID=?
Now, when you have stepped through the wizard, the Fill method of the corresponding data adapter has a new parameter: An employee ID is required! The parameter you send to the Fill method, will be used in the query. Imagine if everything was this easy!
For this example, I have downloaded the Access 2000 Northwind database from http://www.microsoft.com/. If you google on the filename (nwind.mdb), make sure that you download it from Microsoft’s web site.
The problem I have with Crystal Reports is that when I distribute my application, the data source in my report gets invalid, since the connection data refers to a file on my computer, the filename gets invalid when the application is installed on the end users machine.
To solve this problem, the connection data must be dynamically assigned when an end user opens a report.
An application with a Crystal Report usually has a report (rpt-file) added to the project, and a Crystal Report Viewer (a Windows Form with a CrystalReportViewer control). The report file contains the connection string that points to the mdb-file, and the Crystal Report Viewer has a reference to the rpt-file.
All I have to do to simulate the problem, is to rename the mdb-file from nwind.mdb to nwind1.mdb (I close Visual Studio before I do this, to release any locks). Now, Crystal Reports will prompt me for a login ID and a password, since he can’t connect to the file. There is no reason to give a login ID, since the problem is that the file isn’t found (stupid reaction to that error). No matter what I do, the report will not load.
I couldn’t find any information on this, so it took me a while to track how the rpt-file works. This is the solution:
In the form that contains the report viewer, type some code in the control’s Load event, here:
Private Sub CrystalReportViewer1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles CrystalReportViewer1.Load
Declare a variable that can point at the report document:
Dim Doc As CrystalDecisions.CrystalReports.Engine.ReportDocument
You can define your own functions in a PowerShell script file (PS1-file) or directly from the PowerShell console. To do this, use the keyword function, followed by the definition encapsulated in curly brackets. This code creates a function that returns a string containing the phrase “String returned from a function!”:
function myFunction { “String returned from a function!” }
To call this function, simply type myFunction and press Enter. A tip for avoiding typing long lines, you do line breaks by pressing Shift+Enter after the first line. PowerShell then enters a line editing mode. To send the text to PowerShell end exit the line editor, just pres Enter twice. PowerShell might look like this after entering and leaving the line editor:
PS H:\> function myFunction
>> {
>> “String returned from a function!”
>> }
>>
If the function you’re designing requires parameters, you can declare them in a comma separated list directly after the function name. This line defines the sum function that takes two integer parameters and returns the sum of the given values.
function sum([int]$p1, [int]$p2) { $p1+$p2 }
To call a function with parameters, enter the function name followed by the parameter values (constants or variables) separated by nothing but a whitespace.
sum 10 20
To nest the function, encapsulate it in parenthesis. This call returns the value 46:
If you want to call a static function (Shared in Visual Basic) in the .NET Framework, you type in the full name of the class (including the namespaces) followed by double colon (::) and the name of the function you want to call.
The function Load in the Assembly class can be used to load .NET assemblys from the GAC, so if you want to use the .NET Framework, it’s a good start to load the parts of the .NET Framework you need.
Notice that the string argument that is passed to the Load function is fairly complex. There is a chicken version of Load available where you only have to specify the path to the namespace you want to load. The name of that function is LoadWithPartialName, but it is not recommended that you use that function, because it is obsolete. If you are looking for the parameters that needs to be included in the string passed to the Loadfunction, check the properties window of the assembly in your GAC (usually C:\Windows\assembly).
When this is done, you can access the methods of the classes in System.Windows.Forms. This example will show a message box:
[System.Windows.Forms.MessageBox]::Show(“Hello”)
To create instances from classes in any loaded part of .NET Framework, use the New-Object cmdlet.
$x=New-Object System.Windows.Forms.SaveFileDialog
To use New-Object to create COM objects, just add the -comobject parameter to New-Object. If you have Excel installed, this will load and view it. First type:
This new feature saves some time, but for me, it took a while to figure it out. Or to be honest, after a while, I gave up and asked my personal guru Roger. This is the thing:In web services, to preserve session state (that is, being able to read and write session variables across multiple calls) you have to have to declare that the web method uses session state by setting that parameter in the WebMethod attribute. This could be a web method in a web service that reads and/or writes session variables:
<WebMethod(BufferResponse:=False, enableSession:=True)> _
Public Sub SendMails()
…
In .NET 2.0, the client had code that instantiated an object representing the service, assigned a CookieContaner, and then things just worked. My problem (because of sloppy and careless reading on .NET 3.5) was that I didn’t find a property in that object to assign the CookieContainer to. This is how it’s done in .NET 3.5:
Open the config file of the client (the web service consumer). Locate the binding tag, and change the attribute allowCookies from false to true. That’s it! The feature just works! Thanks!
The basic concept of delegates is this: Like a class, you can create instances from a delegate. An instance of a class can represent anything, but an instance of a delegate can only represent a method. A class has a body, a delegate does not need one. Instead, you provide a reference to a function to the delegate constructor. This form calls a method called MySub in the Load event handler:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.MySub(10)
End Sub
Private Sub MySub(ByVal X As Integer)
MessageBox.Show((X * 2).ToString())
End Sub
End Class
If I declare a delegate (the last line), in this case MyDelegate, I could make an instance of the delegate, pass a reference to MySub to the constructor, and then use the delegate to call MySub. Now I have the possibility to pass the delegate around, so that the method can be called by code outside the object, even thou the sub is private. This is used for event handling in Visual Basic.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim X As New MyDelegate(AddressOf MySub)
X(10)
End Sub
Private Sub MySub(ByVal X As Integer)
MessageBox.Show((X * 2).ToString())
End Sub
End Class
Public Delegate Sub MyDelegate(ByVal X As Integer)
Notice how the signature of MySub must match the signature of MyDelegate. If it doesn’t, instances of MyDelegate can’t reference MySub.
Now, let’s say that I add a button to the Form. I want to bind a method to the Click event of that Button (Button1). This what I would have to do to dynamically bind the method: Create the method with the correct signature, user the AddHandler command to bind the method to the Click event of the button. Here is the code for doing that:
Public Class Form1
‘The method…
Private Sub Buttonclick(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show(“Hello”)
End Sub
‘…and the binding.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim H As New EventHandler(AddressOf Buttonclick)
AddHandler Button1.Click, H
End Sub
End Class
I must know the signature that is expected, to be able to bind Buttonclick to the Click event of the Button. That is fair, but what if I don’t need the arguments? Just modifying the signature of Buttonclick will not compile, but I can use relaxed delegates here. Despite the things I have read about relaxed delegates, I can not use them on dynamically bound event handlers. This would work in both Visual Basic 8 and 9:
Public Class Form1
‘The method with declarative binding
Private Sub Buttonclick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MessageBox.Show(“Hello”)
End Sub
End Class
In Visual Basic 9, the Buttonclick method can have a different signature. This will work just as good, and here relaxed delegates are used:
Public Class Form1
‘The method with declarative binding – relaxed!
Private Sub Buttonclick() Handles Button1.Click
MessageBox.Show(“Hello”)
End Sub
End Class
The arguments (sender and e) is no longer available to me, but if I don’t need them that is not a problem. If I want to use arguments, the number of arguments in my handler must be the same, and the type of each argument must be the same or less specific.
In a previous post, I mentioned that Linq could be used to locate the desired codec when you’re saving an image. Instead of iterating through the codecs, and halt when the right one shows up, I could just select the desired one.
This is what I want to do: Load an image, find the JPEG codec, and use that to re-save the image. In Visual Basic 8, the code might look like this:
Dim MyPics As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
Dim B As New System.Drawing.Bitmap(MyPics & “\duck.jpg”)
Dim Codecs() As Imaging.ImageCodecInfo = Imaging.ImageCodecInfo.GetImageEncoders()
For Each Codec As Imaging.ImageCodecInfo In Codecs
If Codec.MimeType = “image/jpeg” Then
‘Create the desiered parameters in a list
Dim HighCompression As New Imaging.EncoderParameter(Imaging.Encoder.Quality, 0)
Dim AllMyParameters As New Imaging.EncoderParameters(1)
AllMyParameters.Param(0) = HighCompression
‘Save the image using the codec and the parameter(s)
B.Save(MyPics & “\high_compression.jpg”, Codec, AllMyParameters)
Exit For
End If
Next
The iteration can be replaced with a Linq expression that simply selects the desired codec. Here, I use a Linq expression to pick the JPEG codec from the list returned from the ImageCodecInfo.GetImageEncoders() function:
Dim Codec As Imaging.ImageCodecInfo = _
(From X In Imaging.ImageCodecInfo.GetImageEncoders() _
Select X Where X.MimeType = “image/jpeg”).First()
So, the complete code that benefits from the new Linq feature looks like this:
‘Load the image I want to re-save
Dim MyPics As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
Dim B As New System.Drawing.Bitmap(MyPics & “\duck.jpg”)
‘Use Linq to locate the right codec
Dim Codec As Imaging.ImageCodecInfo = _
(From X In Imaging.ImageCodecInfo.GetImageEncoders() _
Select X Where X.MimeType = “image/jpeg”).First()
‘Create the desiered parameters in a list
Dim HighCompression As New Imaging.EncoderParameter(Imaging.Encoder.Quality, 0)
Dim AllMyParameters As New Imaging.EncoderParameters(1)
AllMyParameters.Param(0) = HighCompression
‘Save the image using the codec and the parameter(s)
B.Save(MyPics & “\high_compression.jpg”, Codec, AllMyParameters)
This is a good example where Linq actually is useful to make the code shorter and more readable.
This is a really mighty control that mimics the day view in the Outlook calendar. To use the control, add it to your toolbox and then drag the control (named DayView) to a form.
DayView control
It has lots of properties you can use to adjust the behaviour and appearance that you can experiment with. I want to show how to add bookings to the control.
First, you must know what bookings you want to add. In a real application, that information might be loaded from a database into a variable that is declared as a member to the form. In my example, I hard code a couple of bookings.
First, I need an entity that represent a booking. This probably has more fields in a real application (like the primary key of the booking in the database).
Public Class Booking
Public BookingStart As DateTime
Public BookingEnd As DateTime
Public Sub New(ByVal BookingStart As DateTime, ByVal BookingEnd As DateTime)
Me.BookingStart = BookingStart
Me.BookingEnd = BookingEnd
End Sub
End Class
Then, I declare a list of bookings as a member of my form.
Private mBookings As List(Of Booking)
And in the load event of my form, I pretend to load bookings from the database by hard coding a couple of them.
mBookings = New List(Of Booking)()
mBookings.Add(New Booking(New DateTime(2008, 5, 15, 10, 0, 0), New DateTime(2008, 5, 15, 12, 0, 0)))
mBookings.Add(New Booking(New DateTime(2008, 5, 15, 16, 0, 0), New DateTime(2008, 5, 15, 17, 30, 0)))
Also, set the desired start date to the DayView control.
DayView1.StartDate = New DateTime(2008, 5, 15)
Finally, the control will raise the ResolveAppointments event when it wants to know about your bookings. Respond to that by iterating through your loaded bookings, and tell the control about what you want it to show.
Private Sub DayView1_ResolveAppointments(ByVal sender As Object, ByVal args As Calendar.ResolveAppointmentsEventArgs) Handles DayView1.ResolveAppointments
For Each B As Booking In mBookings
Dim A As New Calendar.Appointment()
A.StartDate = B.BookingStart
A.EndDate = B.BookingEnd
args.Appointments.Add(A)
Next
End Sub
There are other events that you could handle, if you want to keep track of what the user is doing with the control.
Visual Basic 9 has a new object initializer. This is the point: Any variable that the code creating the instance can reach, can be initialized using the initializer. This is an example class. It has two public data members (X and Y). Since they are public, they can be initialized using the new object initializer. The ToString function gives information on what data members are initialized.
Public Class SomeClass
Public X As String
Public Y As String
Public Overrides Function ToString() As String
Dim Ret As New System.Text.StringBuilder()
If Me.X Is Nothing Then
Ret.AppendLine(“X = Nothing”)
Else
Ret.AppendLine(“X is initialized”)
End If
If Me.Y Is Nothing Then
Ret.AppendLine(“Y = Nothing”)
Else
Ret.AppendLine(“Y is initialized”)
End If
Return Ret.ToString()
End Function
End Class
This code compiles in both VB8 and VB9:
Dim Obj As New SomeClass()
Obj.X = “Hello”
Debug.WriteLine(Obj.ToString())
The output tells me that X is initialized, and that Y is not. In VB9, I can initialize any of the public members on the same line of code that creates the object. Here, Y is initialized:
Dim Obj As New SomeClass With {.Y = “Yes”}
Debug.WriteLine(Obj.ToString())
And here, both X and Y is:
Dim Obj As New SomeClass With {.X = “I am X”, .Y = “Yes”}
Debug.WriteLine(Obj.ToString())
This can also be used on public properties, and I guess that no-one writes classes that has public variables in production code.
The reason this actually is cool, is that it doesn’t replace your constructors. Using the new object initializer does not bypass the call to the constructor. If, for example, the class doesn’t have a default constructor, but a constructor that takes one argument, the code that creates the instance would look like this:
Dim Obj As New SomeClass(“Hello”) With {.X = “I am X”, .Y = “Yes”}
Instances of the Bitmap class (System.Drawing.Bitmap) represent a bitmapped image. To load an image, just pass the filename to the Bitmap constructor. This example loads a jpeg image from the “my pictures” folder in the current user’s local storage.
Dim MyPics As String = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
Dim B As New System.Drawing.Bitmap(MyPics & “\duck.jpg”)
The supported formats are BMP, GIF, JPEG, PNG and TIFF.
To save the image, just call the function Bitmap.Save of the Bitmap instance, and specify the desired format by passing one of the read only properties in the ImageFormat class as the second argument. This code is saves the loaded image in the Bitmap instance in five different formats.
In some cases, you want to pass arguments to control compression and quality, for example when you save a JPEG image. The Save function has an overloaded version that can take codec parameters as an argument. To use that overload, I need a JPEG codec that can be found in the vector that is returned from the ImageCodecInfo.GetImageEncoders function. This is one piece of code that really would look better if Linq is used, but I do this in Visual Basic 8, so Linq is not available to me.
Dim Codecs() As Imaging.ImageCodecInfo = Imaging.ImageCodecInfo.GetImageEncoders()
For Each Codec As Imaging.ImageCodecInfo In Codecs
If Codec.MimeType = “image/jpeg” Then
‘More code here
Exit For
End If
Next
At the remark “More code here”, I will now add code to actually save the image. This is the complete code for this example:
Dim Codecs() As Imaging.ImageCodecInfo = Imaging.ImageCodecInfo.GetImageEncoders()
For Each Codec As Imaging.ImageCodecInfo In Codecs
If Codec.MimeType = “image/jpeg” Then
‘Create the desiered parameters in a list
Dim HighCompression As New Imaging.EncoderParameter(Imaging.Encoder.Quality, 0)
Dim AllMyParameters As New Imaging.EncoderParameters(1)
AllMyParameters.Param(0) = HighCompression
‘Save the image using the codec and the parameter(s)
B.Save(MyPics & “\high_compression.jpg”, Codec, AllMyParameters)
Exit For
End If
Next
If you run this, you should end up with a picture of very poor quality. The compression (0) is the highest possible, and the file is as small as it can be.
The quality parameter can be a value from 0 to 100, so to get the best possible quality (lowest compression), change the quality parameter to 100, like this:
Dim HighCompression As New Imaging.EncoderParameter(Imaging.Encoder.Quality, 100)
This is the basics in loading and saving bitmap images in .NET 2.0.
The background worker component in .NET Framework is designed to make it easy to execute code in a separate thread. One purpose of writing multithreaded applications might be to allow an application to do heavy work without deteriorating the user experience. An example of this might be searching.
Imagine a form with a single threaded search routine. It might have a textbox for entering a search expression, a search button and a list view that displays the search result. The user is expected type the expression in, click the button and wait for the result.
A multithreaded solution might not require a search button, just a text box and a list view. It will also give the impression of being much faster than the single threaded version. This is how you do it, instead of just doing the search in the click event of the search button:
In the form, declare a Boolean variable that will keep track of the need for doing a search. You will also need a BackgroundWorker control.
In the TextChanged event of the text box, set the Boolean to true. Check if the background worker is already doing something (read the IsBusy property), and if it isn’t, restore the Boolean to false and start the worker. To start the worker call theRunWorkerAsync method of the background worker, and pass the content of the text box as an argument.
In the DoWork event of the background worker, do the search and present the result in the list view. There are a couple of things to keep in mind here.
Finally, in the RunWorkerCompleted event of the background worker, just restart the worker in the same way as you do on the TextChanged event of the text box, if required. (Check the flag, and restore it if you actually start the background worker again.)
This is what you must keep in mind when you present the result:
Have the search result stored in a member variable, so that it can be reached in both the procedure that populates it and the procedure that present it. Remember to call theBeginUpdate and EndUpdate methods of the list view control, to make the update fast. Also, remember that the actual presenting of the result must be done in the GUI thread (that is the main thread), not the thread started by the background worker. So write the code that uses the list view in a separate procedure, and call it using the Invoke method of the form. Pass in a delegate that point to the procedure. The code might look like this:
In the form, add the delegate:
Private Delegate Sub MyThreadSwitcher()
In the code that does the search, call the method that displays the result (in this example it is called RefreshResult) like this:
Dim X As New MyThreadSwitcher(AddressOf Me.RefreshResult)
Me.Invoke(X)
Deep XML support means that the Visual Basic compiler knows what XML is, in about the same way that it knows what a Visual Basic keyword or a string constant is. Since all objects in .NET have a ToString function, wherever you used to use a string with XML data, you can use XML directly. The advantage of this is that any XML syntax errors are detected at compile time. This will work fine: MessageBox.Show(<myXmlElement>Hello!</myXmlElement>.ToString())
To use variable values in your XML, use <%= and %> as delimiter. Example:
Dim X = “Hello!”
MessageBox.Show(<myXmlElement><%= X %></myXmlElement>.ToString())
Imagine the help you get from this when you are sending HTML code to the web browser in an ASP.NET application. Finally, if you need a variable that represents some XML data, the name of the type is XElement in System.Xml.Linq. XElement has a simple API to manipulate and query the XML data.
Dim MyData = <SomeData><Child>1</Child><Child>2</Child></SomeData>
MessageBox.Show(MyData.Nodes().Count().ToString())
About providers and cmdlets: If you just start PowerShell and use these cmdlets, they are for file management.
The Add-Content cmdlet can create a file if it doesn’t exist, and append information to that file. If you execute the following line, you will get a new file in your C root called MyFile.txt.
Add-Content “C:\MyFile.txt” “This is new content.”
The file will contain one line of text (the second parameter). If you run the same command again, the file will contain two lines. If the file exists, information is appended.
There is also a set of commands that can be used to manage files. Your new created file can be moved using the Move-Item cmdlet. Just specify the source and the destination:
Move-Item “C:\MyFile.txt” “D:\MyDestination.txt”
The Copy-Item cmdlet works in the same way, but leaves the original file.
If you don’t want to use absolute paths, you can type Get-Location to find the current directory. Set-Location (or CD for short) changes the current directory.
But again, the reason these cmdlets are used for file management, is that the underlying provider is a FileSystem provider. To see the available providers, type Get-PSProvider. If you change provider from FileSystem to Registry, the cmdlets will be used to manipulate the registry instead of the file system. To change provider to Registry, type:
Set-Location HKLM:
Now, try the Get-Location cmdlet again. This time, it will give you a location in the registry instead of a location in the file system. If you wonder what happened here, type Get-PSDrive. Now you can see what providers are mapped to what drives. The Get-Location cmdlet is used to select an available drive. The provider associated with the drive will also be selected. If you want to use the file system again, just type Set-Location C: (since C: is associated with the FileSystem provider).
When you know about cmdlets and how to get help on them, the next thing is to learn how to use the window.All commands you type in are saved in the command buffer. The keys you use to access the buffer is:
– [Up] for the previous command in the buffer
– [Down] for the next command in the buffer
– [PgUp] for the first and [PgDn] for the last command in the buffer
If you want to move the cursor on the line you are editing for the moment, [Left] and [Right] moves the cursor sideways, [Home] takes you to the first character of the line and [End] takes you to the last one. If you hold [Ctrl] while pressing [Left] or [Right], you move one word at a time, instead of one character.
The [Tab] key is used to auto-complete a word. For example, if you type Write-O and press [Tab],Write-O will be replaced with Write-Output. To pick a command from the buffer, press [F7].
If you want to execute a script, you can create a text file that contains your commands, and execute that, just by entering the scripts path and name. If you want to execute a script (a text file with a ps1 ending) in the directory you’re currently in, and the script file name is “myscript.ps1”:
.\myscript.ps1
PowerShell might complain about the script not being signed. You can remove the requirements for signing by executing this command:
Set-ExecutionPolicy Unrestricted
To test this, create a new text file, type in any commands, for example:
$x=”Sven”
Write-Output $x
Then save it with ps1 file ending, and execute it, just by typing the path and the name of the file.
First of all, your old commands that you used in cmd.exe still work. You have to be a tiny bit stricter in syntax. For example, when you navigate to the parent folder in cmd.exe, you could write:
cd..
In PowerShell, you have to add a space between cd and .., but if you do that, it will work fine.
cd ..
Then, when you approach the new commands (cmdlets) in PowerShell, it might be good to know how to get help. To get a list of all available cmdlets, type Get-Command:
Programmen (cmdlet) i Powershell har namn som består av ett verb, ett bindestreck och ett substantiv, t.ex. Write-Progress. För att få en lista över alla cmdlets, skriv:
Get-Command
All cmdlets have name that consists of a verb and a noun. You should see a list of all cmdlets. If you know the verb, and want to see what available cmdlets that begins with that verb, you add the argument -Verb followed by the actual verb. For example, if you want to see a list of all cmdlets that begin with the verb Move, type:
Get-Command –Verb Move
You now see a list with all cmdlets that begin with the verb Move (Move-Item, Move-ItemProperty).
To get help on a specific cmdlet, type Get-Help followed by the cmdlet. Example:
Get-Help Move-Item
Add the parameter -detailed for a deeper description, or -full for the complete documentation on the cmdlet. This will tell you all there is to know about Move-Item:
Get-Help Move-Item –full