none
DataForm with RIA Services in SL4 "Value does not fall within the expected range" bug

    General discussion

  • There seems to be a bug in Silverlight 4/RIA Services: when a dataform is used to show/allow editing of values in a table in a database, either making a minor change to the record's values and then reversing that change, or even simply tabbing through the fields on the dataform leads (not always, but about 90% of the time!) to the following (spurious, because nothing has changed in the database record) error message:

    "System.ArgumentException: Value does not fall within the expected range."

    Here is example code to reproduce the bug, in a Silverlight 4 project with an accompanying ASP.net website.  

    The MainPage.xaml for the Silverlight project: 

    <UserControl x:Class="TestSLDataBoundBug.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
        xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" 
                 
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    
        <StackPanel x:Name="LayoutRoot" Background="White">
    
            
            <sdk:Label Content="Test of databinding and value falls outside expected range bug   "/>
    
            <sdk:Label Content="Data form bound to RIA services data (problem with changing and resetting date):  "/>
            <toolkit:DataForm x:Name="personalInputForm1" CurrentItem="{Binding}" DataContext="{Binding}" AutoCommit="False" CommandButtonsVisibility="None" >
                <Border Height="30"></Border>
    
                <toolkit:DataForm.EditTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <StackPanel >
                                <sdk:Label Foreground="#003d7c" FontFamily="Arial" FontSize="18" Content="Personal details"/>
                                <sdk:Label Content="   "/>
                            </StackPanel>
    
                            <!-- 02 Apr 2011 try with only one databound field, the data field -->
                            <toolkit:DataField>
                                <toolkit:DataField.Label>
                                    <TextBlock Foreground="#454646"  FontFamily="Arial" FontSize="12" Width="150" TextWrapping="Wrap"><Run Text="Client Name"/></TextBlock>
                                </toolkit:DataField.Label>
                                <StackPanel Orientation="Horizontal">
                                    <TextBox Margin="0,0,10,0" Width="200" Text="{Binding ClientName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" HorizontalContentAlignment="Stretch" />
                                    <sdk:DescriptionViewer Description="Please enter your full name"></sdk:DescriptionViewer>
                                </StackPanel>
                            </toolkit:DataField>
    
                            <toolkit:DataField>
                                <toolkit:DataField.Label>
                                    <TextBlock  Foreground="#454646" FontFamily="Arial" FontSize="12" Width="150"   TextWrapping="Wrap"><Run Text="Own Home Initial Value"/></TextBlock>
                                </toolkit:DataField.Label>
                                <StackPanel Orientation="Horizontal">
                                    <TextBox Margin="0,0,10,0" Width="200" Text="{Binding OwnHomeInitialValue, Mode=TwoWay, Converter={StaticResource ConvertCurrency}, ConverterParameter=N0}" />
                                    <sdk:DescriptionViewer Description="Please enter your current annual salary"></sdk:DescriptionViewer>
                                </StackPanel>
                            </toolkit:DataField>
                            
    
                            <toolkit:DataField>
                                <toolkit:DataField.Label>
                                    <TextBlock  Foreground="#454646" FontFamily="Arial" FontSize="12" Width="150" TextWrapping="Wrap"><Run Text="Date of birth"/></TextBlock>
                                </toolkit:DataField.Label>
                                <!--   Was the following, but try different options to see their effect, doesn't solve the bug, except removing Mode=TwoWay, but that is essential for editing! 
                                <sdk:DatePicker Margin="0,0,40,0" Width="200" SelectedDate="{Binding DateOfBirth, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" HorizontalContentAlignment="Stretch" />
                                -->
                                <sdk:DatePicker Margin="0,0,40,0" Width="200" SelectedDate="{Binding DateOfBirth}" HorizontalContentAlignment="Stretch" />
                            </toolkit:DataField>
    
                        </StackPanel>
                    </DataTemplate>
                </toolkit:DataForm.EditTemplate>
            </toolkit:DataForm>
    <Border Height="30"></Border>
    
    
    
            <sdk:Label Content="Data form bound to CLR object: seems fine "/>
            <toolkit:DataForm x:Name="personForm" CurrentItem="{Binding}" DataContext="{Binding}" AutoCommit="False" CommandButtonsVisibility="None" >
    
                <toolkit:DataForm.EditTemplate>
                    <DataTemplate>
                        <StackPanel>
                                <StackPanel >
                                    <sdk:Label Foreground="#003d7c" FontFamily="Arial" FontSize="18" Content="Personal details"/>
                                    <sdk:Label Content="   "/>
                                </StackPanel>
    
                                <toolkit:DataField>
                                    <toolkit:DataField.Label>
                                        <TextBlock Foreground="#454646"  FontFamily="Arial" FontSize="12" Width="150" TextWrapping="Wrap"><Run Text="Name"/></TextBlock>
                                    </toolkit:DataField.Label>
                                    <StackPanel Orientation="Horizontal">
                                        <!-- 02 Apr 2011 PJL Added margin to add more space between the text box and the description viewer
    										also set the width so that all textboxes are the same width -->
                                        <TextBox Margin="0,0,10,0" Width="200" Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" HorizontalContentAlignment="Stretch" />
                                        <sdk:DescriptionViewer Description="Please enter your full name"></sdk:DescriptionViewer>
                                    </StackPanel>
                                </toolkit:DataField>
    
                                <toolkit:DataField>
                                    <toolkit:DataField.Label>
                                        <TextBlock  Foreground="#454646" FontFamily="Arial" FontSize="12" Width="150"   TextWrapping="Wrap"><Run Text="Salary"/></TextBlock>
                                    </toolkit:DataField.Label>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBox Margin="0,0,10,0" Width="200" Text="{Binding Salary, Mode=TwoWay, Converter={StaticResource ConvertCurrency}, ConverterParameter=N0}" />
                                        <sdk:DescriptionViewer Description="Please enter your current annual salary"></sdk:DescriptionViewer>
                                    </StackPanel>
                                </toolkit:DataField>
    
                            <toolkit:DataField>
                                <toolkit:DataField.Label>
                                    <TextBlock  Foreground="#454646" FontFamily="Arial" FontSize="12" Width="150" TextWrapping="Wrap"><Run Text="Date of birth"/></TextBlock>
                                </toolkit:DataField.Label>
                                <sdk:DatePicker Margin="0,0,40,0" Width="200" SelectedDate="{Binding DateOfBirth, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" HorizontalContentAlignment="Stretch" />
                            </toolkit:DataField>
    
                        </StackPanel>
    	            </DataTemplate>
                </toolkit:DataForm.EditTemplate>
            </toolkit:DataForm>
    
    
        </StackPanel>
    </UserControl>
    

    Here is the corresponding (C#) code behind for MainPage, MainPage.xaml.cs:

    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;
    
    using System.ComponentModel; // added for IPropertyChanged
    using System.Windows.Data; // added for IValueConverter
    using TestSLDataBoundBug.Web; // NB I had to add the web project as the WCF RIA Services link in the Silverlight project's Silverlight properties for this statement to be accepted
    using System.ServiceModel.DomainServices.Client; // 17 Feb 2011 PJL added, needed for EntityQuery
    
    namespace TestSLDataBoundBug
    {
        public partial class MainPage : UserControl
        {
            Person _person;
            PersonalInput _personalInput;
            DomainService1 _context;
            LoadOperation<PersonalInput> _personalInputOperation;
    
            public MainPage()
            {
                InitializeComponent();
    
                _person = new Person();
                _person.Name = "Smith";
                _person.Salary = 10000;
                _person.DateOfBirth = new DateTime(1955, 7, 1);
                personForm.DataContext = _person;
    
                _context = new DomainService1();
                EntityQuery<PersonalInput> personalInputQuery = _context.GetPersonalInputsQuery();
                personalInputQuery = personalInputQuery.Where(p => p.RunID == 5);
                _personalInputOperation = _context.Load(personalInputQuery);
                _personalInputOperation.Completed += new EventHandler(_personalInputOperation_Completed);
    
            }
    
            void _personalInputOperation_Completed(object sender, EventArgs e)
            {
                _personalInput = _personalInputOperation.Entities.FirstOrDefault();
                personalInputForm1.DataContext = _personalInput;
            }
        } // class
    
        public class Person : INotifyPropertyChanged
        {
            private string name;
            public string Name
            {
              get { return name;}
                set {
                    if (value != name)
                    {
                        name = value;
                        NotifyPropertyChanged("Name");
                    }
                }
            }
    
            private double salary;
            public double Salary
            {
              get { return salary;}
                set {
                    if (value != salary)
                    {
                        salary = value;
                        NotifyPropertyChanged("Salary");
                    }
                }
            }
    
            private DateTime dateOfBirth; 
            public DateTime DateOfBirth
            {
                get { return dateOfBirth; }
                set
                {
                    if (value != dateOfBirth)
                    {
                        dateOfBirth = value;
                        NotifyPropertyChanged("DateOfBirth");
                    }
                }
            }
    
    
            private void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
        } // class Person
    
        // 03 Mar 2011 PJL added to help the dataforms to display numbers in currency format (otherwise get validation errors when fields are edited)
        /// <summary>
        /// 
        /// </summary>
        public class CurrencyToNumberConverter : IValueConverter
        {
            public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null || parameter == null)
                    return value;
    
                double dAnswer;
                if (double.TryParse(value.ToString(), out dAnswer))
                    return "£" + dAnswer.ToString(parameter.ToString()); // parameter should be something like "N0" for £1,234
                else
                    // this leads to unhandled run time error, so better to return DependencyProperty.UnsetValue
                    //throw new System.Exception("Error in CurrencyToNumberConverter: could not convert the following value to a currency value: " + value.ToString());
                    return DependencyProperty.UnsetValue;
            }
    
            public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null || parameter == null)
                    return value;
    
                // 23 Jul 2011 added to catch a situation where a client 2 numeric field is blank
                if ("" == value.ToString())
                    return 0;
    
                // 14 Mar 2011 amended to allow for the situation where the user overtypes the currency symbol
                //// first remove the currency symbol (expected to be, but not necessarily £)
                //string str1 = value.ToString().Substring(1).Trim();
                //double dAnswer;
                //if (double.TryParse(str1, out dAnswer))
                //    return dAnswer;
                string str1 = value.ToString().Trim().Substring(0, 1);
                double dAnswer;
                if (double.TryParse(str1, out dAnswer))
                    // the first character is numeric, so probably isn't a currency symbol
                    str1 = value.ToString().Trim();
                else
                    // remove the currency symbol (expected to be, but not necessarily £)
                    str1 = value.ToString().Trim().Substring(1);
                if (double.TryParse(str1, out dAnswer))
                    return dAnswer;
                else
                    // this leads to unhandled run time error, so better to return DependencyProperty.UnsetValue
                    //throw new System.Exception("Error in CurrencyToNumberConverter: could not convert back the following value to a real number: " + value.ToString());
                    return DependencyProperty.UnsetValue;
            } // ConvertBack
    
        } // CurrencyToNumberConverter
    
    } // namespace
    

    The database table that is linked to is called PersonalInputs and is in a database called TestFinPlanner3.

    These names are obviously not important as long as the Entity Data Model and Domain Service in the web project are configured correctly to pick up the relevant fields from the table.

    For simplicity, I am deliberately not using all the fields in the table, but can reproduce the problem with just 3 fields: ClientName (text), OwnHomeInitialValue (float) and DateOfBirth (date).  

    The SQL to create the database table is:

    USE [TestFinPlanner3]
    GO
    
    /****** Object:  Table [dbo].[PersonalInputs]    Script Date: 09/15/2011 16:47:14 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    SET ANSI_PADDING ON
    GO
    
    CREATE TABLE [dbo].[PersonalInputs](
    	[RunID] [int] NOT NULL,
    	[ThisIsInputsForPerson2] [bit] NOT NULL,
    	[ClientName] [varchar](30) NOT NULL,
    	[DateOfBirth] [date] NOT NULL,
    	[OwnHomeInitialValue] [float] NOT NULL,
     CONSTRAINT [PK_PersonalInputs] PRIMARY KEY CLUSTERED 
    (
    	[RunID] ASC,
    	[ThisIsInputsForPerson2] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    SET ANSI_PADDING OFF
    GO
    
    ALTER TABLE [dbo].[PersonalInputs]  WITH CHECK ADD  CONSTRAINT [FK_PersonalInputs_Runs] FOREIGN KEY([RunID])
    REFERENCES [dbo].[Runs] ([RunID])
    GO
    
    ALTER TABLE [dbo].[PersonalInputs] CHECK CONSTRAINT [FK_PersonalInputs_Runs]
    GO
    

    Just in case this is relevant (I doubt it), here is the sql for the related Runs table (again, I haven't shown all the fields for simplicity)

    USE [TestFinPlanner3]
    GO
    
    /****** Object:  Table [dbo].[Runs]    Script Date: 09/15/2011 16:55:14 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    SET ANSI_PADDING ON
    GO
    
    CREATE TABLE [dbo].[Runs](
    	[RunID] [int] IDENTITY(1,1) NOT NULL,
    	[Comments] [varchar](300) NULL,
     CONSTRAINT [PK_Runs] PRIMARY KEY CLUSTERED 
    (
    	[RunID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    SET ANSI_PADDING OFF
    GO
    

    For completeness I add that the Silverlight project needs to have references to System.ServiceModel, System.ServiceModel.DomainServices.Client (also Client.Web), System.Windows.Controls.Data (also Data.DataForm.Toolkit, Data.Input, Data.Toolkit), DataVisualization.Toolkit, System.Windows.Controls.Input.Toolkit, System.Windows.Controls.Toolkit (and Toolkit.Internals). 

    Also, here is App.xaml (where I had to add a CurrencyToNumberConverter as a Resource):

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 x:Class="TestSLDataBoundBug.App"
                 
      xmlns:app="clr-namespace:TestSLDataBoundBug"             
                 
                 >
        <Application.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary>
                        <!-- 03 Mar 2011 PJL added -->
                        <app:CurrencyToNumberConverter x:Key="ConvertCurrency" />
                    </ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Application.Resources>
    </Application>
    

    I also had to add an else branch to the default if (!System.Diagnostics.Debugger.IsAttached) branch in App.xaml.cs

    (for some reason, the default code leaves out any error trapping for the situation when the code is run via debug in Visual Studio!):

           private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
            {
                // If the app is running outside of the debugger then report the exception using
                // the browser's exception mechanism. On IE this will display it a yellow alert 
                // icon in the status bar and Firefox will display a script error.
                if (!System.Diagnostics.Debugger.IsAttached)
                {
    
                    // NOTE: This will allow the application to continue running after an exception has been thrown
                    // but not handled. 
                    // For production applications this error handling should be replaced with something that will 
                    // report the error to the website and stop the application.
                    e.Handled = true;
                    Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
                }
    
                else // 24 Jul 2011 PJL added (for some reason, the default code had only put in code for when the if statement applied!
                {
                    e.Handled = true; // 05 Sep 2011 added, otherwise we get an Unhandled exception message after the MessageBox.Show command
                    Exception ex = e.ExceptionObject;
                    MessageBox.Show("An error occurred and the system message was: " + ex.Message, "TestSLDataBoundBug", MessageBoxButton.OK);
                }
    
            } // Application_UnhandledException

    If anyone knows of any solution, or a workaround, please let me know!

    Thanks,

    Patrick

    Thursday, September 15, 2011 12:09 PM

All replies

  • Hello Patrick,

    What was the call stack when the exception was thrown? You may find which method was called and then an ArgumentException was thrown. Please also check the parameter name and value that causes the ArgumentException.

    Thanks,
    Carson

    Wednesday, September 21, 2011 10:56 PM
  • Thanks, but the call stack is no help because it shows "[ExternalCode]" as the last thing that happened before the error.  Similarly, stepping through the code with the debugger doesn't help either, unless there is some way to get into the "External code" (presumably Silverlight or RIA services system code?). 

    NB I've just checked, and the bug is still there in Silverlight 5 within Visual Studio 11 Preview, so it is not just confined to Silverlight 4.

    Patrick

    Sunday, October 02, 2011 11:55 AM
  • I was not able to reproduce the issue. Can you please provide a complete sample project and step for us to reproduce the issue?

    Thanks,
    Carson

    Tuesday, October 18, 2011 3:04 AM