Sujay V Sarma: Feedback on Some WPF APIs
Sujay V Sarma posts "WPF Controls — A better way to be" with the following Summary:
"Next release: Microsoft, please fix .NET 3.0 and make it simpler to use?"
Sujay – We are always eager to improve WPF in every way we can. Thanks for being vocal with feedback.
The issues he raises:
KeyPress – does it exist
For instance, while WPF documentation mentions a "KeyPress" event, I could find only "KeyDown" and "KeyUp" listed everywhere.
RR: please tell me the URLs of any pages that do this, so we can correct. (Better yet, add the comments to the page yourself.)
SS: Rob, you may want to look at: this one where you’re clearly saying "Provides data for the KeyPress event".
RR: That page is for Windows Forms…sorry for the confusion. System.Windows.Forms existed before WPF, but we chose to use System.Windows.* as the base namespace. So it appears that WinForms APIs are in the middle of WPF.
Usability of KeyEventArgs
Then it turned out there was no way to find out the actual key pressed. For instance, KeyDown has a System.Windows.Input.KeyEventArgs argument. This has a "Key" property that returns a parsed (in some Microsoft pre-ordained silly way) value. The worst part of that is that if you’re looking for an alphabet character, you will always only get a capital letter! AWFUL.
RR: I believe we do this kind of thing to handle all types of input, including those that include IME. Is your scenario just one of trying to see if "a" or "b" is typed? Please give details.
SS: I was trying to make myself a Password textbox with some additional features. This is fairly straightforward coding in VB6/VB7, thanks to both the KeyPress/KeyUp/KeyDown events and the direct raw character code I can retrieve from the event’s arguments. But here, since you’re pre-processing the key for me and giving it to me in a format I have no use for, I cannot implement this control at all. Imagine, all entered passwords will be forced to uppercase!
RR: Yes, building a PasswordBox is difficult given our v3 apis, I’d agree. I’ll give this feedback to the owners of the WPF TextBox and see how they plan to address this. I believe they generally would like to see people able to write to a higher level event (like TextChanged) that handles IME, paste(?), etc…
Luckily we wrote a PasswordBox already in v3, so you should be ok for now. Would also love to know any other scenarios that are difficult with our TextBox… Thanks for the feedback!
Why is Visibility an Enum?
And then I’m used to writing "X.Visible = True" and having become visible. Whether with Win32 apps or ASP.NET ones. I grant that the statement in WPF would be "X.Visibility = Windows.Visibility.Visible"
RR: We wrestled with this in the design of WPF. HTML has two concepts Visible and Display. We ended up combining them into one property, that is a tri-state.
Should things become topmost when I set visibility to Visible?
this doesnt bring ALL objects to the front. I was trying for example to simulate a Popup control using a Panel. This just wouldnt work (the panel would never popup).
RR: you may need to set the ZIndex on a Panel to ensure it would be on top. (ZIndex is set as an attached property, it is defined by Panel.)
SS: I did try this Rob, but the Popup just would not pop up. I then had to resort to a textbox on a Canvas control and use the ZIndex with that.. Have some small bugs in this at the moment like with its positioning, but those can be ironed out.
RR: Check out this example of Implicit ZIndex, Explicit ZIndex and Popup.
Having to cast too much?
Most things return an object of type "UIElement" or one of its many relatives. This makes it impossible to look up properties without first casting it explicitly into the proper type — which is impossible to guess programmatically. For instance if I had made a Container Control, I would never know an enumerated item at runtime was a Textbox or a Button from its properties.
RR: would love specific scenarios to discuss.
SS: At work, I had a task of determining the best way we could add annotation capabilities to all controls on a form. The orignal forms were in .NET 2.0 and we wanted to test out the capabilities of WPF for the next release. The simple way seemed to be to rewrite the Control level template for the application with the required triggers and sub-controls, etc. But, since this control could now contain ANYTHING, how would the code at runtime know if it was dealing with a textbox or a button or a listbox or a combobox, whose templates themselves may have been customized for some forms? If one had to do a TypeName to figure out what a control was, and cast it to the appropriate object variables so that we could do safe-binding, I would have atleast variable for each type of control in .NET. And you know better than I do, how many such controls there are.
RR: Interesting…response coming…
Difference between IsMouseOver and IsMouseDirectlyOver
One last thing — There are two properties for a mouse-event argument: one is "IsMouseOver" and the other is "IsMouseDirectlyOver". I was using the latter for a while till I realized that for some reason it stayed FALSE all the time.
RR: IsMouseDirectlyOver’s documentation says:
Unlike IsMouseOver, this property is only true if the mouse pointer is over the literal element—as it is for a hit test. If the mouse pointer is instead over a child element, in particular over elements that are part of an element’s deeper template and compositing, this property will be false. Unless you know how a control is composited (for example, you use this property in a custom control template for a control that you define), this property might return unexpected results. For most scenarios where you are not authoring controls, use IsMouseOver instead.
Sorry for the confusion.
Extent of the Window
SS: And, while we’re still on this page, just how exactly can a WPF code figure out the extent of the Window that’s being displayed? Since every control can be inside every other control, thanks to the weird concept of "Hold’em All Templates", one would have NO idea at runtime how many levels deep a particular control is.
RR: this.ActualHeight and this.ActualWidth should give you the Window’s actual size. We have Actual* becuase with our layout system sometimes you are given a size differently than you asked for it. For example, size to content allows a button to not specify a Height or Width, but it will have one.
Designed for Xaml Only
SS: Apparently, WPF has been designed only from the XAML front with little or no thought to how to write code in the code-behinds!
RR: In the end, yes, we shipped a v3 that needs more support on the API front (convenience constructors). However, we did spend a lot of time to ensure our APIs were well designed. Keep the feedback coming…so we know what needs the most help.
Common Dropdown MenuItem
SS: And while you are at it, could you also tell me how I can add a common dropdown menu item to ALL the controls in my app? This one is quite confusing. There also does not seem to be a way without first trapping the information in a MouseOver event to find out which element on a form among others a menu click came from. For instance, if I have 2 instances of a TextBox that I have customized and added a custom contextmenu to, when a MenuItem.Click occurs, how do I know which of the two textboxes I am processing??? The Source and OriginalSource of the event args are set to the MenuItem that was clicked and this is not helpful at all…
RR: Response coming…