locked
DataBinding + Inheritance

    Question

  • Hey,

    I have a User Control with a custom DependencyProperty.
    The type is BaseClass.

    The hierarchy looks like that:

    class BaseClass { ... }

    class OtherClass : BaseClass { ... }
    /* Other class inherits from BaseClass and overrides some methods + some properties (with new) */

    I bound the property to a property Base of another class.
    However when I set the Base to an instance of OtherClass the UserControls property is set to null.
    If I set it to an instance of BaseClass there is absolutely no problem.
    Can anyone explain why that happens and how I fix it?
    I guess I could fix it by listening to property changes instead of using DataBinding but I would prefer to use DataBinding.
    Wednesday, April 22, 2015 8:58 PM

All replies

  • Hi St3f4n,

    Could you please try to post a simple reproduce project in here? I want to have a test in my side.
    Thanks for your understanding.

    Best Regards,
    Amy Peng


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, April 23, 2015 6:21 AM
    Moderator
  • Sure.
    Here you go:

    Project: C# Blank App (Windows)
    App.xaml(.cs): Not modified

    MainPage.xaml:

    <Page
        x:Class="SampleAppBinding.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:SampleAppBinding"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="200">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <local:CustomUserControl x:Name="customUserControl" Grid.ColumnSpan="4"/>
            <Button Grid.Row="1" Grid.Column="0" Tag="0" Content="SampleBase1" Click="Button_Click"/>
            <Button Grid.Row="1" Grid.Column="1" Tag="1" Content="SampleBase2" Click="Button_Click"/>
            <Button Grid.Row="1" Grid.Column="2" Tag="2" Content="SampleBase3" Click="Button_Click"/>
            <Button Grid.Row="1" Grid.Column="3" Tag="3" Content="SampleOther1" Click="Button_Click"/>
        </Grid>
    </Page>
    


    MainPage.xaml.cs (Only the content):

    public MainPage()
    {
        this.InitializeComponent();
    
        Binding bindingBase = new Binding();
        bindingBase.Source = StaticClass.Instance;
        bindingBase.Path = new PropertyPath("Base");
        customUserControl.SetBinding(CustomUserControl.BaseProperty, bindingBase);
    }
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        switch ((sender as Button).Tag as string)
        {
            case "0":
                StaticClass.Instance.Base = new BaseClass("BaseClass 1");
                break;
            case "1":
                StaticClass.Instance.Base = new BaseClass("BaseClass 2");
                break;
            case "2":
                StaticClass.Instance.Base = new BaseClass("BaseClass 3");
                break;
            case "3":
                StaticClass.Instance.Base = new OtherClass("OtherClass 1");
                break;
        }
    }


    CustomUserControl.xaml:

    <UserControl
        x:Class="SampleAppBinding.CustomUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:SampleAppBinding"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400"
        x:Name="cucRoot">
        
        <Grid>
            <TextBlock x:Name="textBlockTest" Text="{Binding Base.Text, ElementName=cucRoot}"/>
        </Grid>
    </UserControl>

    CustomUserControl.xaml.cs:

    public static DependencyProperty BaseProperty = DependencyProperty.Register("Base", typeof(BaseClass), typeof(CustomUserControl), new PropertyMetadata(null));
    public BaseClass Base { get { return GetValue(CustomUserControl.BaseProperty) as BaseClass; } set { SetValue(CustomUserControl.BaseProperty, value); } }
    
    public CustomUserControl()
    {
        this.InitializeComponent();
    }


    StaticClass.cs:

    public class StaticClass : INotifyPropertyChanged
    {
        public static StaticClass Instance = new StaticClass();
    
        public BaseClass _base;
        public BaseClass Base { get { return _base; } set { _base = value; firePropertyChanged("Base"); } }
    
        private StaticClass() {}
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void firePropertyChanged(params string[] properties)
        {
            if (PropertyChanged != null)
            {
                foreach (string property in properties)
                    PropertyChanged(StaticClass.Instance, new PropertyChangedEventArgs(property));
            }
        }
    }


    BaseClass.cs:

    public class BaseClass
    {
        public string Text { get; private set; }
    
        public BaseClass(string Text)
        {
            this.Text = Text;
        }
    }

    OtherClass.cs:

    public class OtherClass : BaseClass
    {
    
        public OtherClass(string Text) : base(Text)
        {
        }
    }


    I tried it and could reproduce the null issue.
    You can set a break point at the switch in MainPage.xaml.cs to look at it. Just set a watch on customUserControl.

    Thursday, April 23, 2015 9:15 AM
  • Still haven't figured out how to solve this.
    Using a converter doesn't help. But it gets called.
    Saturday, April 25, 2015 3:20 PM
  • However when I set the Base to an instance of OtherClass the UserControls property is set to null.
    If I set it to an instance of BaseClass there is absolutely no problem.

    We should convert the inheritance type to the base type.

    Monday, May 25, 2015 7:15 AM
  • Could you be a  little more precise?
    When setting Base to an instance of OtherClass, the instance of OtherClass should be autocasted to BaseClass afaik.
    Thursday, May 28, 2015 12:49 PM