none
How to add my custom control to DataForm?

    Question

  • I need to add a custom control to SilverLight DataForm. I know there is a way to do on .xaml side, but is a little bit inconvenient because in this case I will need to do this for each class. I have read here http://weblogs.asp.net/naughton/archive/2009/08/01/silverlight-3-dataform-control-mapping-basic-modifications.aspx suggestion to modify SilverLight SDK, but it does not look like fine. Actually, I need to add two kinds of custom controls: 1. Assign List to ComboBox; 2. To have one TextBox + button (and I need to handle this button, of course). I'm going to provide this information via meta data for each field, but I don't know how to make DataForm so flexible. Thanks in advance!
    Monday, March 22, 2010 3:39 PM

All replies

  • You can replace the TextBox with your control on DataForm.OnAutoGeneratingField event handler.

    Take a look at CustomDataForm.cs code that comes with the Silverlight Business Application Project. The Login Form is using a CustomDataFrom. It replace TextBox with a PasswordBox for password field in OnAutoGeneratingField event.

     

    Monday, March 22, 2010 4:09 PM
  • Thank you for the quick response. Unfortunately, the project you are talking about is available only in VS 2010 and I don't have it. Could you please provide me a little example from CustomDataForm.cs file? I have found only this one in the Internet: protected override void OnAutoGeneratingField(DataFormAutoGeneratingFieldEventArgs e) { // normally change this condition to check it is one of your complex types // or that it is not a basic type. if (e.PropertyType == typeof(NestedComplexType)) { var control = new SuperDataForm(); control.CommandButtonsVisibility = DataFormCommandButtonsVisibility.All; control.IsReadOnly = false; Controls.Add(control); Binding binding = new Binding(e.PropertyName); binding.Mode = BindingMode.TwoWay; binding.ValidatesOnExceptions = true; binding.NotifyOnValidationError = true; control.SetBinding(DataForm.CurrentItemProperty, binding); e.Field.IsReadOnly = false; e.Field.Content = control; } } Should I add my custom control here: e.Field.Content = control; instead of "control"?
    Monday, March 22, 2010 4:53 PM
  • Silverlight Business Application project template is not available in VS2008 with Silverlight 3?

    Anyway it has more than one file involved:

    DataFieldExtensions.cs:

     

     public static class DataFieldExtensions
        {
            /// <summary>
            ///     Replaces a <see cref="DataField" />'s <see cref="TextBox" /> control with another control,
            ///     taking care of automatically updating the bindings.
            /// </summary>
            /// <param name="newControl">The new control you're going to set as <see cref="DataField.Content" /></param>
            /// <param name="dataBindingProperty">The control's property that will be used for data binding</param>        
            public static void ReplaceTextBox(this DataField field, FrameworkElement newControl, DependencyProperty dataBindingProperty)
            {
                field.ReplaceTextBox(newControl, dataBindingProperty, binding => { });
            }
    
            /// <summary>
            ///     Replaces a <see cref="DataField" />'s <see cref="TextBox" /> control with another control,
            ///     taking care of automatically updating the bindings and overriding the existing converter
            ///     with another one
            /// </summary>
            /// <param name="newControl">The new control you're going to set as <see cref="DataField.Content" /></param>
            /// <param name="dataBindingProperty">The control's property that will be used for data binding</param>        
            /// <param name="bindingSetupFunction">
            ///     A function you can use to change parameters on the newly generated binding before
            ///     it is applied to <paramref name="newControl"/>
            /// </param>
            public static void ReplaceTextBox(this DataField field, FrameworkElement newControl, DependencyProperty dataBindingProperty, Action<Binding> bindingSetupFunction)
            {
                // Construct new binding by copying existing one, and sending it to bindingSetupFunction
                // for any changes the caller wants to perform
                Binding newBinding = field.Content.GetBindingBLOCKED EXPRESSION;
                bindingSetupFunction(newBinding);
    
                // Replace field
                newControl.SetBinding(dataBindingProperty, newBinding);
                field.Content = newControl;
            }
        }

    CustomDataForm.cs:

     public class CustomDataForm : DataForm
        {
    
           protected override void OnAutoGeneratingField(DataFormAutoGeneratingFieldEventArgs e)
            {
                // Get metadata about the property being defined
                PropertyInfo propertyInfo = this.CurrentItem.GetType().GetProperty(e.PropertyName);
                  
                // Do the password field replacement if that is the case           
                if (e.Field.Content is TextBox && this.IsPasswordProperty(propertyInfo))
                {
                    e.Field.ReplaceTextBox(new PasswordBox(), PasswordBox.PasswordProperty);
                }
    
                // Keep this newly generated field accessible through the Fields property
                this.fields[e.PropertyName] = e.Field;
    
                // Call base implementation (which will call other event listeners)
                base.OnAutoGeneratingField(e);
            }
    
           protected virtual bool IsPasswordProperty(PropertyInfo propertyInfo)
            {
                // Suggestion: to handle more complex scenarios, allow an entity to override
                // this mechanism by using the System.ComponentModel.DataAnnotations.UIHintAttribute
                return propertyInfo.Name.IndexOf("Password", StringComparison.InvariantCultureIgnoreCase) != -1;
            }
    
    } 
     
    Monday, March 22, 2010 5:07 PM
  • Thanks for the code. Unfortunately, I was not able to compile it. It seems my DataFom control doesn't have some methods that your DataForm has. E.g. this.fields[e.PropertyName] = e.Field; this line is not compilable because if "fields". But doesn't matter. I got the idea. I have written a simple example: public class MyClass { public string MyString { get; set; } public List<string> MyList { get; set; } } then I initialize my DataFom MyClass MyTest = new MyClass { MyString = "test string", MyList = new List<string> { "1", "2", "3" } }; CardDataForm.CurrentItem = MyTest; and then I override the function: protected override void OnAutoGeneratingField(DataFormAutoGeneratingFieldEventArgs e) { if (e.PropertyType == typeof(List<string>)) { ComboBox control = new ComboBox(); Binding binding = new Binding(e.PropertyName); control.SetBinding(ComboBox.SelectedItemProperty, binding); e.Field.IsReadOnly = false; e.Field.Content = control; } } The only problem is how to add my data to the new combobox. I found only one way: control.ItemsSource = ((MyClass)CurrentItem).MyList; and it works, but can't use this way because I'm going to have a several different classes. I saw how it's done in original DataForm control, but there we have the Data and Type in one variable. In my case there are two different variables: e - with information about type and etc. and CurrentItem with my class itself. I didn't get how to get only one particular field of my class using information provided in "e" variable. BTW, sorry but it writes everything in one line and ignore my "" tegs, I don't know why.
    Tuesday, March 23, 2010 3:39 AM
  • Add the following line in your CustomDataForm:

    public class CustomDataForm : DataForm
        {
            private Dictionary<string, DataField> fields = new Dictionary<string, DataField>();

            /// <summary>
            ///     Returns a <see cref="Dictionary" /> containing all the <see cref="DataForm" />
            ///     <see cref="DataField" /> controls being displayed keyed by the
            ///     property name to which each field is bound
            /// </summary>
            public Dictionary<string, DataField> Fields
            {
                get { return this.fields; }
            }

             ...

    }

    Tuesday, March 23, 2010 10:20 AM
  • Thank you so much! You help is very appreciated. But could you please help me to understand the following line: Binding newBinding = field.Content.GetBindingBLOCKED EXPRESSION; Especially, right part of this. If it possible, please send my the Silverlight Business Application Project via e-mail (probably this forum blocks some text) to ostupnikov(@)gmail.com Thanks in advance!
    Tuesday, March 23, 2010 5:25 PM
  • I spend one complete day to figure out how to dispaly silverlight datagrid summary columns still no idea. I am using SL5+ER4 + Domain datasource.  (I don't know how long it will take to finished products like Telrik for silverlight ppl). Its annoying sometimes.

      Col1 | Col2 | Col3 | Col4     | Col_Total

                                                     

              1        2        3         4           11

              5        6        7         8           26

    =================================

    Total : 6        8        10      blah       blah

    =================================  

    I have already went to various blogs and tried this.----------->


    DataColumn sumCol;
    sumCol = new DataColumn("Total", typeof(double));
    sumCol.Expression = "ColumnA + ColumnB + ColumnC + ColumnD";
    ds.Tables["TableName"].Columns.Add(sumCol);


    IEnumerable<AllocationLine> list = allocationLineDataGrid.ItemsSource.OfType<AllocationLine>();
    decimal Total = list.Sum(p => (decimal)p.GetType().GetProperty("/*Amount*/").GetValue(p, null));

    Anyy one having the same problem ?

    Thnks.

    Friday, March 09, 2012 6:58 PM