Friday, December 30, 2011

Silverlight Screen Disabling When Closing ChildWindow

An obnoxious problem has been plaguing a project that I've been working on for the last couple of months. As we would be testing various pieces of functionality, the screen would inexplicably become completely disabled. Now, we were working in a TabbedPane, so it was quite odd that the entire browser screen was being disabled (and not just our current Tab). Well, as I'm sure you realize - this is not acceptable production behavior! So, as we began drawing closer to our release date, this became more of a pressing concern - and so I was able to dedicate several hours to investigating the problem (and now writing this so that I didn't forget the solution!)

Ok, here are the steps I found to reproduce.
  1. Go to a certain tab
  2. Bring up the ChildWindow
  3. Click the "X" (built in Close) button
  4. Go to a different tab
  5. Bring up a different ChildWindow
  6. Close the new ChildWindow
  7. *poof* your screen was disabled!

So, if you're like me, you assume that the problem is in the second ChildWindow - after all, that's the one showing the symptoms... except that it works most of them time - just not when you go to the other ChildWindow first.

Anyway, I scoured the Internet looking for anyone that was having any kind of similar problems. There were people talking about setting both a DialogResult and calling the Close() method, so I looked for that. Nothing.

There were people that talked about calling Close() twice (setting DialogResult actually calls Close() so this is really the same as the last problem). I looked all over the ChildWindow that was exhibiting the symptoms - still nothing.

What actually happened was that my FIRST ChildWindow was calling Close() from the Closing event handler, because it was calling an inherited block of code without realizing all of the implications - and this somehow decided to mess up the next ChildWindow's close operation. Who knew?

So, long story short - if you're experiencing a disabling of your main screen when a ChildWindow closes, look for Close() to be called twice - but be mindful of Close() being called on a previous ChildWindow after it is already in the Closing event handler as well!

Wednesday, November 2, 2011

Validation States on TextBox in Silverlight

So, one of the requirements on the project that I'm working on is that we have a Silverlight TextBox that has to display the error balloon/tooltip. Simple, right? However, this TextBox is actually just displaying data, and the data is entered through a dialog, not directly as text on the screen. Furthermore, to ensure that the user does not attempt to enter the data directly, the TextBox is disabled.

You may know where I'm going with this - my Validation Error tooltip never appears! Why? The default style of a TextBox only shows the tooltip in a focused state! Eventually, I realized this. After looking in the MSDN documentation about TextBox, I was able to get the default style of a TextBox, and I was able to override it's InvalidUnfocused state to do the same as the InvalidFocused state - and it worked!

Now to find a more intuitive way for the user to see that error message without it always being on the screen...

Sunday, September 25, 2011

Why is my Silverlight DataForm acting like that?

The other day, as I was using Silverlight, I put a DataGrid inside of a DataForm. Seems innocent enough, right? Specifically, what I wanted to accomplish was to allow users to add elements to a DataGrid with drag and drop functionality. Therefore, there were two DataGrids - one that the user dragged from, and the other that would receive the drop event. What I noticed, though, was that the added elements were not being saved.

We are using WCF RIA services, so I first assumed that I had created my composition objects incorrectly, and so I spent quite a bit of time looking into and verifying that code. After adding more and more breakpoints, I discovered that the WCF RIA service call was not to blame - the added elements were not even in the Submit operation, and so they were being removed sometime before the Submit was called.

Next, life got even more strange - if I edited one of the DataFields on the DataGrid, and then I dragged an item over, everything saved correctly. This left me quite puzzled. Then, eventually, a co-worker helped me discover the problem (which I thought was strange enough to warrant a blog post - maybe this will help other people (or even myself) next time one of us runs into this situation).

A Silverlight DataForm Rejects changes on EditEnded.

What? Yeah, I thought that this was quite strange. Why was I hitting this event? My "Save" button was not in the DataGrid! However, once you know this, it is easy enough to fix. Handle the EditEnding event on the DataForm and mark the event canceled:

private void DataForm_EditEnding(object sender, DataFormEditEndingEventArgs e)
{
       e.Cancel = true;
}

Done! Now my DataForm stopped rejecting my changes.

Tuesday, July 5, 2011

Making Values Required in a Silverlight DataForm

For those of you who have done validation in a Silverlight DataForm before, you probably are used to setting the [Required] attribute above all of the necessary fields in your WCF RIA project. From there, .NET will auto-magic the necessary code and, combined with lots of NotifyOnValidationError and ValidatesOnExceptions tags (and potentially some GetBindingExpression().UpdateSource()), viola! it will successfully perform validations. However, I ran into a situation where I was actually taking a couple of fields and transforming them into a single field from my WCF RIA service data object. After a long time of scratching my head, I was really stuck on trying to figure out how to force this validation to work. I had tried setting the [Required] attribute on the field they were bound to, added all the usual NotifyOnValidationError tags... nothing.

Eventually, I realized how to get around this issue (and it made me feel a bit silly for not coming up with this earlier.) You know where we set "ValidatesOnExceptions=true"... well... let's throw a ValidationException! So, in the setter of the property that I was binding the DataField to, if the data was invalid, I simply threw a ValidationException. Poof! It suddenly started working. Is there a better way to do this? Probably. However, this was able to get me back on the right path, and I was able to resume being productive.

Friday, April 1, 2011

Systematically Update Binding in Silverlight

So, after quite a bit of time in Silverlight, I have learned that DataForms are very powerful entities.  However, they like to hide from me what they are doing.  Therefore, when I get into a situation in which I need to simulate their behavior, this often ends with me banging my head against a wall and typing my query into Google in as many different ways as possible.  Recently, I have been attempting to force a validation on an object that was not in a DataForm... and I had no idea how.  Fortunately, I stumbled upon this forum and it helped me.  So that you don't have to bother reading it (that's why you're at my site, anyway, isn't it?) I have placed the important code snippet here:

BindingExpression bindingExpression = myTextBox.GetBindingExpresion(TextBox.TextProperty);
bindingExpression.UpdateSource();

Poof!  Your TextBox (assuming your TextBox variable is called "myTextBox") will validate.

Thursday, February 17, 2011

Silverlight Data Forms with BusyIndicator

So, I'm sure that this has been posted elsewhere, but I don't really remember where, so I figured I would re-post it if for no other reason than it would allow me to find it again.


When using Silverlight 4 with the toolkit, I ran into an interesting bug.  Sometimes when I would use a DataForm along with the toolkit's BusyIndicator, the DataForm would appear to be disabled, even after the BusyIndicator was no longer showing.  (To see more about the bug itself, you can go here.)  After discovering what the issue was, I researched on Google how I should fix this.  As it turns out, it is a pretty simple fix. I simply added the following (note that DataForm is the variable name of the DataForm in my XAML):

DataForm.IsEnabledChanged += new DependencyPropertyChangedEventHandler(DataForm_IsEnabledChanged);

and

        void DataForm_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!IsEnabled)
            {
                VisualStateManager.GoToState(DataForm, "Disabled", true);
            }
            else
            {
                VisualStateManager.GoToState(DataForm, "Normal", true);
            }
        }


Poof!  The code was able to go back to the correct state.  Hopefully Microsoft will fix this so that this workaround is no longer required, but in the meantime, I figured it might help someone to see this.