DataForm error when using a custom field control that extends from TextBox

1 Answer 120 Views
DataForm
Daniel
Top achievements
Rank 1
Daniel asked on 14 May 2021, 01:03 AM

Hey,

I am using DataForm with custom field to display one of my complex properties for editing.
I am having an issue with Null reference exceptions from within the Telerik DataForm code when my control extends from a textbox. 

I have reproduced the issue in a small sample app that doesn't have any of the complexities of my actual application.
What happens is if you run the application and click Ok or Cancel on the dataform buttons it will through a null reference exception.
This only happens if the HotKeyInputBox extens from a TextBox, if it extends from a Button or other type of control it doesn't throw the exception. Based on my implementation I need to extend it from a TextBox. I can't see any reason it should be throwing an exception.

Any help with getting this working would be fantastic.

MainWindow.xaml

<Window x:Class="DataFormBugDemo.MainWindow"
                 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:local="clr-namespace:DataFormBugDemo"
                 xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
                 mc:Ignorable="d"
                 Title="MainWindow" Height="450" Width="800">
    <Grid>
        <telerik:RadDataForm CurrentItem="{Binding Source={x:Static local:Setting.Instance}}" 
                             AutoEdit="True" AutoGenerateFields="True" AutoGeneratingField="RadDataForm_OnAutoGeneratingField"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Data;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Data.DataForm;

namespace DataFormBugDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            StyleManager.ApplicationTheme = new Office2019Theme();
            Office2019Palette.LoadPreset(Office2019Palette.ColorVariation.Dark);
            InitializeComponent();
        }

        private void RadDataForm_OnAutoGeneratingField(object sender, AutoGeneratingFieldEventArgs e)
        {
            e.DataField.DataMemberBinding.NotifyOnSourceUpdated = true;
            e.DataField.DataMemberBinding.NotifyOnValidationError = true;
            e.DataField.DataMemberBinding.ValidatesOnDataErrors = true;
            e.DataField.DataMemberBinding.ValidatesOnNotifyDataErrors = true;
            e.DataField.DataMemberBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            if (e.PropertyType == typeof(HotKey))
            {
                var dataField = new DataFormHotKeySettingsField()
                {
                    Label = e.DataField.Label,
                    DataMemberBinding = e.DataField.DataMemberBinding,
                    Description = e.DataField.Description
                };
                e.DataField = dataField;
            }
        }
    }
}

DataFormHotKeySettingsField.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Telerik.Windows.Controls;

namespace DataFormBugDemo
{
    public class DataFormHotKeySettingsField : DataFormDataField
    {
        protected override DependencyProperty GetControlBindingProperty()
        {
            return HotKeyInputBox.HotKeyProperty;
        }

        protected override Control GetControl()
        {
            var dependencyProperty = GetControlBindingProperty();
            var inputBox = new HotKeyInputBox();
            if (DataMemberBinding != null)
            {
                var binding = DataMemberBinding;
                binding.Mode = BindingMode.TwoWay;
                inputBox.SetBinding(dependencyProperty, binding);
            }
            inputBox.SetBinding(IsEnabledProperty, new Binding("IsReadOnly") { Source = this, Converter = new InvertedBooleanConverter() });
            return inputBox;
        }
    }
}

HotKeyInputBox.cs

using System.Windows;
using System.Windows.Controls;

namespace DataFormBugDemo
{
    class HotKeyInputBox : TextBox
    {
        public static readonly DependencyProperty HotKeyProperty = DependencyProperty.Register(
            "HotKey", typeof(HotKey), typeof(HotKeyInputBox), new PropertyMetadata(default(HotKey)));

        public HotKey HotKey
        {
            get { return (HotKey)GetValue(HotKeyProperty); }
            set { SetValue(HotKeyProperty, value); }
        }

        public static readonly DependencyProperty DisplayTextProperty = DependencyProperty.Register(
            "DisplayText", typeof(string), typeof(HotKeyInputBox), new PropertyMetadata(default(string)));

        public string DisplayText
        {
            get { return (string)GetValue(DisplayTextProperty); }
            set { SetValue(DisplayTextProperty, value); }
        }

        public HotKeyInputBox()
        {
            DisplayText = "None";
        }
    }
}

HotKey.cs

using System.Windows.Input;

namespace DataFormBugDemo
{
    public class HotKey
    {
        public bool IsEnabled { get; set; }

        public Key Key { get; set; }
    }
}

Setting.cs

using PropertyChanged;

namespace DataFormBugDemo
{
    [AddINotifyPropertyChangedInterface]
    public class Setting
    {
        public static Setting Instance { get; }
        static Setting()
        {
            Instance = new Setting();
        }

        public string Name { get; set; } = "Test Name";

        public HotKey HotKey { get; set; } = new HotKey();
    }
}

App.xaml

<Application x:Class="DataFormBugDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:DataFormBugDemo"
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
      <!-- HotKeyInputBox -->
      <ControlTemplate x:Key="HotKeyInputBoxTemplate" TargetType="local:HotKeyInputBox">
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
          </Grid.ColumnDefinitions>
          <Border Grid.Column="0" BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"
                  Padding="0" Name="PART_Border" VerticalAlignment="Center">
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{TemplateBinding DisplayText}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Foreground="{TemplateBinding Foreground}"
                         MinWidth="150" Margin="0" />
            </StackPanel>
          </Border>
        </Grid>
      </ControlTemplate>

      <Style TargetType="local:HotKeyInputBox">
        <Setter Property="Template" Value="{StaticResource HotKeyInputBoxTemplate}" />
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="BorderBrush" Value="{telerik:Office2019Resource ResourceKey=MainBorderBrush}" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="Background" Value="{telerik:Office2019Resource ResourceKey=SecondaryBackgroundBrush}" />
        <Setter Property="Foreground" Value="{telerik:Office2019Resource ResourceKey=MainForegroundBrush}" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />

      </Style>
    </Application.Resources>
</Application>


1 Answer, 1 is accepted

Sort by
0
Accepted
Vladimir Stoyanov
Telerik team
answered on 18 May 2021, 11:24 AM

Hello Daniel,

I replied in the ticket that you have opened on the same topic, however I will post my answer here as well for completeness.

I investigated the demonstrated scenario and the reason for the observed behavior is that the RadDataForm expects fields with a TextBox editor to have a binding to the Text property of the TextBox.

With this in mind, you can make sure to create a binding and set it to the Text property of the custom TextBox when initializing it. I am attaching back the sample project demonstrating what I have in mind. Note, that the only relevant change is inside the GetControl method of the DataFormHotKeySettingsField class. 

Regards,
Vladimir Stoyanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
DataForm
Asked by
Daniel
Top achievements
Rank 1
Answers by
Vladimir Stoyanov
Telerik team
Share this question
or