I'm having a go at making a Silverlight2 UserControl to emulate the basic functionality of a WinForms MessageBox. I was following Shawn Wildermuth and John Papa's examples.
Compiles fine, I add the user control to my app with a button to show the popup. This works - popup appears, you can click a button to close it and it closes. You can do this multiple times.
The problem appears if the UserControl that contains the "MessageBox" is closed and a new one created. If you try and open the popup on the new instance, it throws an exception:
Unhandled Error in Silverlight 2 Application
Code: 4004
Category: ManagedRuntimeError
Message: System.ArgumentException: Value does not fall within the expected range.
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.FrameworkElement_MeasureOverride(FrameworkElement element, Size availableSize)
at System.Windows.FrameworkElement.MeasureOverride(Size availableSize)
...
(stack trace doesnt go as far as any of my code)
The code for the control is at the bottom of the post. If you want to run it, I've made a testbench project to demonstrate the problem. The testbench has on-screen instructions to tell you how to reproduce the problem.
This has been driving me nuts, so any help or pointers would be greatly appreciated.
Here is the code for the PopupMessage user control:
<UserControl x:Class="SilverlightPopupControlTest.PopupMessage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
>
<Grid x:Name="LayoutRoot">
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="PopupState" CurrentStateChanged="PopupState_CurrentStateChanged">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition GeneratedDuration="00:00:00.2000000"/>
<vsm:VisualTransition GeneratedDuration="00:00:00.2000000" To="PopupStateOpened"/>
<vsm:VisualTransition GeneratedDuration="00:00:00.2000000" To="PopupStateClosed"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState x:Name="PopupStateClosed">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PopupFillGrid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#00FFFFFF"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="PopupStateOpened">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PopupFillGrid" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#BFFFFFFF"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="border" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Popup x:Name="PopupControl">
<Grid x:Name="PopupFillGrid">
<Grid.Background>
<SolidColorBrush Color="#00ffffff"/>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="1" Grid.Column="1" RenderTransformOrigin="0.5,0.5" x:Name="border" Opacity="0" >
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<ContentPresenter x:Name="PopupContentPresenter"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="Button1" Click="Button1_Click" Margin="4" MinWidth="80">
<ContentPresenter x:Name="Button1ContentPresenter"/>
</Button>
<Button x:Name="Button2" Click="Button2_Click" Margin="4" MinWidth="80">
<ContentPresenter x:Name="Button2ContentPresenter"/>
</Button>
<Button x:Name="Button3" Click="Button3_Click" Margin="4" MinWidth="80">
<ContentPresenter x:Name="Button3ContentPresenter"/>
</Button>
</StackPanel>
</Grid>
</Border>
</Grid>
</Popup>
</Grid>
</UserControl>
and its code-behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightPopupControlTest
{
public partial class PopupMessage : UserControl
{
#region PopupContent Dependency Property
public UIElement PopupContent
{
get { return (UIElement)GetValue(PopupContentProperty); }
set { SetValue(PopupContentProperty, value); }
}
public static readonly DependencyProperty PopupContentProperty = DependencyProperty.Register(
"PopupContent", typeof(UIElement), typeof(PopupMessage), new PropertyMetadata(PopupContentChanged));
private static void PopupContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnPopupContentChanged((UIElement)e.OldValue, (UIElement)e.NewValue);
}
private void OnPopupContentChanged(UIElement oldValue, UIElement newValue)
{
this.PopupContentPresenter.Content = newValue;
}
#endregion
#region Button1Visibility Dependency Property
public Visibility Button1Visibility
{
get { return (Visibility)GetValue(Button1VisibilityProperty); }
set { SetValue(Button1VisibilityProperty, value); }
}
public static readonly DependencyProperty Button1VisibilityProperty = DependencyProperty.Register(
"Button1Visibility", typeof(Visibility), typeof(PopupMessage), new PropertyMetadata(Button1VisibilityChanged));
private static void Button1VisibilityChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton1VisibilityChanged((Visibility)e.OldValue, (Visibility)e.NewValue);
}
private void OnButton1VisibilityChanged(Visibility oldValue, Visibility newValue)
{
this.Button1.Visibility = newValue;
}
#endregion
#region Button2Visibility Dependency Property
public Visibility Button2Visibility
{
get { return (Visibility)GetValue(Button2VisibilityProperty); }
set { SetValue(Button2VisibilityProperty, value); }
}
public static readonly DependencyProperty Button2VisibilityProperty = DependencyProperty.Register(
"Button2Visibility", typeof(Visibility), typeof(PopupMessage), new PropertyMetadata(Button2VisibilityChanged));
private static void Button2VisibilityChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton2VisibilityChanged((Visibility)e.OldValue, (Visibility)e.NewValue);
}
private void OnButton2VisibilityChanged(Visibility oldValue, Visibility newValue)
{
this.Button2.Visibility = newValue;
}
#endregion
#region Button3Visibility Dependency Property
public Visibility Button3Visibility
{
get { return (Visibility)GetValue(Button3VisibilityProperty); }
set { SetValue(Button3VisibilityProperty, value); }
}
public static readonly DependencyProperty Button3VisibilityProperty = DependencyProperty.Register(
"Button3Visibility", typeof(Visibility), typeof(PopupMessage), new PropertyMetadata(Button3VisibilityChanged));
private static void Button3VisibilityChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton3VisibilityChanged((Visibility)e.OldValue, (Visibility)e.NewValue);
}
private void OnButton3VisibilityChanged(Visibility oldValue, Visibility newValue)
{
this.Button3.Visibility = newValue;
}
#endregion
#region Button1Content Dependency Property
public UIElement Button1Content
{
get { return (UIElement)GetValue(Button1ContentProperty); }
set { SetValue(Button1ContentProperty, value); }
}
public static readonly DependencyProperty Button1ContentProperty = DependencyProperty.Register(
"Button1Content", typeof(UIElement), typeof(PopupMessage), new PropertyMetadata(Button1ContentChanged));
private static void Button1ContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton1ContentChanged((UIElement)e.OldValue, (UIElement)e.NewValue);
}
private void OnButton1ContentChanged(UIElement oldValue, UIElement newValue)
{
this.Button1ContentPresenter.Content = newValue;
}
#endregion
#region Button2Content Dependency Property
public UIElement Button2Content
{
get { return (UIElement)GetValue(Button2ContentProperty); }
set { SetValue(Button2ContentProperty, value); }
}
public static readonly DependencyProperty Button2ContentProperty = DependencyProperty.Register(
"Button2Content", typeof(UIElement), typeof(PopupMessage), new PropertyMetadata(Button2ContentChanged));
private static void Button2ContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton2ContentChanged((UIElement)e.OldValue, (UIElement)e.NewValue);
}
private void OnButton2ContentChanged(UIElement oldValue, UIElement newValue)
{
this.Button2ContentPresenter.Content = newValue;
}
#endregion
#region Button3Content Dependency Property
public UIElement Button3Content
{
get { return (UIElement)GetValue(Button3ContentProperty); }
set { SetValue(Button3ContentProperty, value); }
}
public static readonly DependencyProperty Button3ContentProperty = DependencyProperty.Register(
"Button3Content", typeof(UIElement), typeof(PopupMessage), new PropertyMetadata(Button3ContentChanged));
private static void Button3ContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((PopupMessage)o).OnButton3ContentChanged((UIElement)e.OldValue, (UIElement)e.NewValue);
}
private void OnButton3ContentChanged(UIElement oldValue, UIElement newValue)
{
this.Button3ContentPresenter.Content = newValue;
}
#endregion
public enum PopupMessageResult
{
Unknown=0,
Button1=1,
Button2,
Button3
}
#region PopupMessageClosed Event
public class PopupMessageClosedEventArgs : EventArgs
{
public PopupMessage.PopupMessageResult Result { get; set; }
public PopupMessageClosedEventArgs()
{
}
public PopupMessageClosedEventArgs(PopupMessage.PopupMessageResult _Result)
{
this.Result = _Result;
}
}
public delegate void PopupMessageClosedEventHandler(object sender, PopupMessageClosedEventArgs e);
public event PopupMessageClosedEventHandler PopupMessageClosed;
protected virtual void OnPopupMessageClosed(PopupMessageClosedEventArgs e)
{
if (PopupMessageClosed != null)
{
PopupMessageClosed(this, e);
}
}
#endregion
private PopupMessageResult m_Result = PopupMessageResult.Unknown;
public PopupMessageResult Result
{
get { return m_Result; }
set { m_Result = value; }
}
private FrameworkElement m_HostControl = null;
public FrameworkElement HostControl
{
get { return m_HostControl; }
set { m_HostControl = value; }
}
public PopupMessage()
{
InitializeComponent();
this.Button1Visibility = Visibility.Collapsed;
this.Button2Visibility = Visibility.Collapsed;
this.Button3Visibility = Visibility.Collapsed;
VisualStateManager.GoToState(this, "PopupStateClosed", false);
}
private void Close()
{
VisualStateManager.GoToState(this, "PopupStateClosed", true);
}
public void Show()
{
this.PopupControl.IsOpen = true;
this.Visibility = Visibility.Visible;
this.TabNavigation = KeyboardNavigationMode.Cycle;
this.Button1.Focus();
VisualStateManager.GoToState(this, "PopupStateOpened", true);
}
void PopupState_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
{
if (e.NewState.Name == "PopupStateClosed")
{
this.PopupControl.IsOpen = false;
this.Visibility = Visibility.Collapsed;
this.OnPopupMessageClosed(new PopupMessageClosedEventArgs(this.Result));
}
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
this.Result = PopupMessageResult.Button1;
this.Close();
}
private void Button2_Click(object sender, RoutedEventArgs e)
{
this.Result = PopupMessageResult.Button2;
this.Close();
}
private void Button3_Click(object sender, RoutedEventArgs e)
{
this.Result = PopupMessageResult.Button3;
this.Close();
}
}
}