Pardon my rant, but the thing I currently hate most about Silverlight (besides copious XML) is the Visibility property. Any sane framework would implement Visibility as a Boolean. Not Silverlight though. It’s creators in undoubted infinite wisdom implemented it as an enumeration. The values of the enumeration? There are two: Visible and Collapsed. Hmmm.
Of course this causes superfluous verbosity in common everyday code:
button1.Visibility = makeVisible ? Visibility.Visible : Visibility.Collapsed;
Or worse when things get a little more complex:
// don't display the panel if its button's aren't visible
panel1.Visibility =
!(button1.Visibility == Visibility.Visible &&
button2.Visibility == Visibility.Visible) ?
Visibility.Visible :
Visibility.Collapsed;
Clearly this was done to keep Silverlight compatible with the Windows Presentation Foundation (WPF) which has three values in its enumeration property (Visible, Hidden, and Collapsed). But that’s just as ridiculous. Why WPF couldn’t use two properties, Visible (Boolean) and NotVisibleBehavior (enumeration) is beyond me.
It’s ok though, because .Net 3.0 gave me a cure to any Framework shortcomings: Extension Methods. A syntactic sugar cure for all my bitterness:
public
static void
SetVisible(this
FrameworkElement element, bool visible) {
element.Visibility = visible ?
Visibility.Visible :
Visibility.Collapsed;
}
public static
bool IsVisible(this
Visibility visibility) {
return
visibility == Visibility.Visible;
}
Fantastic, now my "complex" example becomes:
// don't display the panel if its button's aren't visible
panel1.SetVisible(!(button1.IsVisible() && button2.IsVisible()));
Still not quite as nice as a Boolean visible property, but certainly doable.
3.0 Limitation #1, By Ref Extension Methods
But wait. Isn’t it best practice in Silverlight to use binding for these types of things? Separation of logic from presentation and all. So I should do:
<StackPanel Visibility="{Binding IsPanelVisible}">
And then:
public
class DisplayStuff
: INotifyPropertyChanged {
public
Visibility IsPanelVisible { get;
private set; }
public
void UpdateStatus(bool
makeVisible) {
IsPanelVisible = makeVisible ?
Visibility.Visible :
Visibility.Collapsed;
// make
sure to notify the control that the property has changed
PropertyChanged(this, new
PropertyChangedEventArgs("IsPanelVisible"));
}
}
And we can set the DataContext of some parent element to an instance of DisplayStuff and all the children including our panel magically databind. That’s cool, but the ugliness is back (well, not as bad since I removed the buttons to simply the example, but you can pretend). This is because we extended FrameworkElement not Visibility. No problem, just extend Visibility right?
public
static void
SetVisible(this
Visibility visibility, bool visible) {
visibility = visible ?
Visibility.Visible :
Visibility.Collapsed;
}
Except this doesn’t work. Can you spot the problem?
It compiles. It runs. But the value of IsPanelVisible never changes. Oh yea, C# is pass by value by default. And now the .Net Framework 3.0 limitation. This isn’t possible:
public static void SetVisible(this ref Visibility visibility, bool visible) {
You get "The parameter modifier 'ref' cannot be used with 'this'." Grr.
Limitation #2, By Ref Automatic Properties
Ok, so remove “this”, and go back to C# 2.0 helper functions which extension methods are syntactic sugar for anyway:
public static void SetVisible(ref Visibility visibility, bool visible) {
And now our class can do:
ExtensionMethods.SetVisible(ref IsPanelVisible, makePanelVisible);
Right? Not so fast I’m afraid. Compile error. “A property or indexer may not be passed as an out or ref parameter”. And I guess this is reasonable. You can’t pass the address of a function, which is what a property is in the background. So you should pass the private variable that backs the property.
Except that I don’t have one! I used an automatic property. And .Net doesn’t let me access the private variable backing the automatic property. So I’m stuck!
And this is .Net 3.0 limitation #2. Automatic properties are wonderful until you try to do much with them. Why couldn’t the framework notice that I’m using an automatic property and pass the variable that I can’t access by ref to my function?
And now I find myself back in a .Net 2.0 world because all the features I like so much in 3.0 are more sugar than substance.
Conclusion
Allowing automatic properties to pass by reference or allowing access to the private member behind them would be nice. Allowing extension methods to change the instance they extend would be nice. But ultimately none of this would be a problem if Visible had been implemented as a Boolean. The way every other framework in the world does. </Complaining>
Comments
The reason is the ambiguity in the call
DoSomething(true, false, true)
is not very readable.
However, booleans as properties are allowed because they are very readable. They must have decided to use an enum for the sake of compatibility with WPF.
Re: Booleans as method parameters, I guess I can agree that they aren't readable, but unfortunately we don't have extension properties yet, only extension methods. Maybe in C# 4.0 :).
http://msdn.microsoft.com/en-us/library/system.windows.uielement.visibility(VS.95).aspx
It says:
"The reason that Visibility uses an enumeration rather than a simple Boolean is that this area of the Silverlight object model is modeled on the Windows Presentation Foundation (WPF) Visibility property, which uses a three-state model for Visibility of Visible/Hidden/Collapsed. In the WPF model, Hidden denotes a visibility state where the object should not render, but should still occupy space in a WPF layout. Silverlight version 1.0 does not support a Hidden visibility state, but still uses the Visibility enumeration values that remain (Visible, Collapsed). If you are importing XAML UI definitions from WPF, you might need to change the cases where a Visibility is declared as Hidden in order to use that XAML in Silverlight."
So there is your answer :)
If a developer codes like this:
DoSomething(true, false, true)
they need to be shot :) j/k...but a better practice would be passing descriptive variables:
bool isPostBack = true;
DoSomething(isPostBack);
...eliminates the readability aspect of the code. PLUS enumerations have their PITA aspects :)
its..uh.. C programming..will you please help me? :(
i need help :(