Thoughts on WPF / Silverlight
While developing quite a simple Silverlight application a few months ago I noticed how lagish it can become. Now I came across this article, and after realizing I wasn't imagining things I'm starting to realize how immature WPF and Silverlight are. And that is without mentioning some severe bugs WCF has - and you can't use Silverlight properly without a WCF host.
Here are a few snippets from the article and comments:
How many times have you had to scale back you UI because it was too jerky? How many times have you came up with the “groundbreaking new UX model” that you had to scrap because the technology couldn’t handle it? How many times have you told a customer they require a 2.4ghz quad core to get the full experience? I’ve been asked by customers why they cannot deliver the same fluid UX they have on their iPad application using WPF or Silverlight on a PC with four times the horses. This technology may be good enough for line-of-business applications, but it falls short of being able to deliver a next generationconsumer application.
I get the same question from other developers and management: “why do phone applications running on dinky ARM processors feel so much smoother?”
Then I will see some cool HTML5 canvas example posted on Reddit, check the CPU loading it causes, and think there’s no way I could do that in WPF without 2x the loading. Even jquery widgets seem to behave more responsively than my WPF app.
My 2 cents: if you're looking to create a rich UI for the desktop, take a look at HTMLayout (.NET bindings here); I find the way XAML data bindings work too clumsy anyway. For web experiences, you should be all set with jQuery and HTML5; if you're looking to create games you should use Flash.
NAppUpdate first release: 0.1
NAppUpdate (pronounced: nap-date), a small and flexible open-source library providing consumer applications with auto-update functionality, is now being officially released, and is ready for production.
About a month ago I released a first version of my local copy of the library, and posted this first post with some info and code samples showing how to use it from any .NET application. The response I received was tremendous, compared to the short time frame. I wish there was a way to know how wide its usage is now!
I would like to thank Andrew Rowson and Jamie Lennox for jumping in to make several code tweaks based on their experience with the library - mainly to resolve issues with non-privileged users. NAppUpdate is now confirmed to work very well on Windows 7, Vista and XP. Thanks guys!
The post mentioned above is a bit outdated now. Also, there are quite a few features I'd like to see added to the library, such as status reporting and a more flexible handling of tasks and rollbacks. Andrew, Jamie and I have already discussed several ways of tackling those features, hopefully you'll see them in soon. Right after the API stabilizes, I will work on creating some documentation in the library's git-wiki space on github, so anyone can jump-start easily with using it.
So far it has been a great experience. Hopefully the marking of version 0.1 will encourage more users and collaboration. See you again soon with 0.2!
NAppUpdate, available freely from: http://github.com/synhershko/NAppUpdate (ASL 2.0)
Binaries and a sample app with source: http://github.com/synhershko/NAppUpdate/downloads
(Edit) A user/developer discussion group is now available at: http://groups.google.com/group/nappupdate
NAppUpdate – Application auto-update framework for .NET
Any desktop applications programmer finds himself every now and then looking for a library providing an application auto-update functionality, that is flexible and easy-to-integrate. I had the intention of working on such a library for some time now, so it will do things the way I want it to. Last week I got to actually doing it, and I'm quite satisfied with the results.
NAppUpdate can be integrated easily with any .NET application - WinForms or WPF, and it offers great flexibility through interfaces, for feed readers, file sources, and update tasks. It also supports conditional updates, the implementation of which offers unlimited extendibility.
I based my work on Lee Treveil's .NET-Auto-Update, and although I practically rewrote almost everything, he certainly deserves this credit.
The library, released under the Apache 2.0 software license, can be downloaded / cloned from http://github.com/synhershko/NAppUpdate. Please share your thoughts, or any extension you make to it.
Update 30/03/2011: A user/developer discussion group is now available at: http://groups.google.com/group/nappupdate
Update 30/09/2010: although most of the post below is still true, it is already (!) a bit outdated. Please check the NAppUpdate tag in this blog for the latest information on the library.
At the time of this writing, here is what NAppUpdate offers:
Better splitter behavior for HTMLayout
The implementation of the splitter behavior which comes with HTMLayout, and its .NET wrapper in Nabu, suffers from several issues: it doesn't take into account RTL layouts, and the actual resizing is done while dragging the splitter itself - which is quite costly. As a result of the latter, 2 on_size notifications were pushed for every sizing operation instead of one.
I perfected it so it uses a "ghost" element to mark the splitter's position while dragging, and the actual layout changes occur only once its released from capture. Also, it now works correctly in RTL layouts, and many graphical glitches are prevented.
The code below is meant to be used with the .NET Nabu wrapper; porting it to be native HTMLayout C++ behavior is quite easy. Some more generalization work may be required before you can implement it in your solution.
using System;
using System.Collections.Generic;
using System.Text;
using Nabu.Forms.Html;
namespace MyApp.UI
{
[HtmlBehaviorName("splitter")]
public sealed class HtmlSplitterBehavior : HtmlBehaviorBase
{
#region HtmlSplitterBehavior
#region Fields
private bool _isCaptured;
private bool _isHorizontal;
private bool _isRTL;
private HtmlTag _parent;
private HtmlTag _prevSibling;
private HtmlTag _nextSibling;
private string _className;
private int _startPrevSize;
private int _startPosition;
#endregion
#region Methods
public HtmlSplitterBehavior()
: base(HtmlEventGroup.InitializationAndMouse)
{
}
#endregion
#endregion
#region HtmlBehaviorBase
protected override void OnMouse(HtmlTag sender, HtmlMouseEventArgs e)
{
if ((e.MouseState & HtmlEventMouseState.Left) != 0)
{
switch (e.Command)
{
case HtmlMouseEventCommand.Down:
{
using (HtmlTag splitter = e.Target)
{
HtmlTag parent = splitter.Parent;
HtmlTag leftSibling = splitter.PrevSibling;
HtmlTag rightSibling = splitter.NextSibling;
if ((parent != null) && (leftSibling != null) && (rightSibling != null))
{
this._parent = parent;
_isRTL = splitter.GetState(HtmlTagState.IsRTL);
this._prevSibling = leftSibling;
this._nextSibling = rightSibling;
this._isHorizontal = this._parent.GetStyle("flow") == "horizontal";
if (this._isHorizontal)
{
splitter.SetStyle(_isRTL ? "left" : "right",
e.PositionInDocument.X.ToString() + "px");
this._startPosition = e.PositionInDocument.X;
this._startPrevSize = this._prevSibling.GetLocation(HtmlTagArea.RootRelative).Width;
}
else
{
splitter.SetStyle("top", e.PositionInDocument.Y.ToString() + "px");
this._startPosition = e.PositionInDocument.Y;
this._startPrevSize = this._prevSibling.GetLocation(HtmlTagArea.RootRelative).Height;
}
splitter.SetStyle("height", this._parent.GetLocation(HtmlTagArea.BorderBox).Height + "px");
this._className = splitter.Attributes["class"];
splitter.Attributes["class"] = "splitter_ghost";
splitter.SetCapture();
this._isCaptured = true;
e.IsHandled = true;
}
}
}
break;
case HtmlMouseEventCommand.Up:
if (this._isCaptured)
{
using (HtmlTag splitter = e.Target)
{
splitter.Attributes["class"] = _className;
if (this._isHorizontal)
{
splitter.SetStyle("height", null);
int prevSize = this._startPrevSize;
if (_isRTL)
prevSize += (e.PositionInDocument.X - this._startPosition) * -1;
else
prevSize += (e.PositionInDocument.X - this._startPosition);
this._prevSibling.SetStyle(
"width",
prevSize + "px");
this._nextSibling.SetStyle(
"width",
"100%%");
}
else
{
int prevSize = this._startPrevSize + (e.PositionInDocument.Y - this._startPosition);
this._prevSibling.SetStyle(
"height",
prevSize + "px");
this._nextSibling.SetStyle(
"height",
"100%%");
}
}
this._parent = null;
this._prevSibling = null;
this._nextSibling = null;
HtmlTag.ReleaseCapture();
this._isCaptured = false;
e.IsHandled = true;
}
break;
case HtmlMouseEventCommand.Move:
if (this._isCaptured)
{
using (HtmlTag splitter = e.Target)
{
splitter.SetStyle(_isRTL ? "left" : "right", e.PositionInDocument.X.ToString() + "px");
}
e.IsHandled = true;
}
break;
}
}
base.OnMouse(sender, e);
}
#endregion
}
}
The splitter element is defined in my CSS as follows:
#mainsection > hr {padding:0;border:none;margin:0;width:0; height:*;hit-margin:3px; behavior:splitter;cursor:w-resize;}
#mainsection > hr.splitter_ghost { border: 1px solid #999; position:absolute;}
Testing hspell’s language coverage using Wikipedia
As part of the HebMorph project, I needed to test hspell's dictionary on a large modern corpus. Knowing how many words it can recognize is very important, and below I'll be explaining exactly why.
The project, along with usage instructions, is released under the GNU GPL and available from here. The report (zipped XML) is available here.
Open-source Hebrew information retrieval (HebMorph, part 3)
Indexing Hebrew texts for later retrieval is not a trivial task. Although several solutions exist, I have pointed out that they are not necessarily providing the best results. Either way, there is no freely available solution allowing to index Hebrew even at the very basic level.
HebMorph was started with this in mind. It is a free, open-source effort for making Hebrew properly searchable by various IR software libraries, while maintaining decent recall, precision and relevance in retrievals. During the work on this project, we will try and come up with different approaches to indexing Hebrew, and provide the tools to perform reliable comparisons between them. This project's ultimate goal is providing various IR libraries with the best Hebrew IR capabilities possible.
BusyObject: Easily get .NET WinForms apps look busy
Imagine you are working on a .NET WinForms application, and it has many small user tasks which require you to disable all input controls in your form. What happens if each of those also has quite a lot of possible exit points? returning and re-enabling the GUI in all of them is quite a pain.
The following code allows you to do this all in just 2 extra lines of code: