Search code examples
.netdata-bindingmvvm

Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'


I wonder if anyone can help. I have been banging my head against this problem for half a day now, I must be doing something wrong. I have a custom control with a number of dependency properties.

    [TemplatePart(Name = InformationBubble.InformationBubbleTitlePart, Type = typeof(TextBlock))]
    [TemplatePart(Name = InformationBubble.InformationBubbleProductImagePart, Type=typeof(Image))]

    public class InformationBubble : Control 
    {
        #region Template Parts Name Constants

        /// <summary>
        /// Name constant for the Information Bubble Title Part
        /// </summary>
        public const string InformationBubbleTitlePart = "InformationBubbleTitleText";

        /// <summary>
        /// Name constant for the Information Bubble Product Image Part
        /// </summary>
        public const string InformationBubbleProductImagePart = "InformationBubbleProductImage";

        #endregion

        #region TemplateParts

        private TextBlock _Title;

        internal TextBlock Title
        {
            get { return _Title; }
            private set
            {
                _Title = value;

                if (_Title != null)
                {
                    _Title.Text = this.ProductTitleText;       
                }
            }
        }

        private Image _ProductImage;

        internal Image ProductImage
        {
            get { return _ProductImage; }
            private set
            {
                _ProductImage = value;

                if (_ProductImage != null)
                {
                    _ProductImage.Source = this.ProductImageSource;
                }
            }
        }

        #endregion

        #region Public String Product Title 

        // Dependency properties declaration
        public static readonly DependencyProperty ProductTitleProperty = DependencyProperty.Register(
            "ProductTitle",
            typeof(string),
            typeof(InformationBubble),
            new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnProductTitleChanged)));

        public static void OnProductTitleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            InformationBubble iBubble = sender as InformationBubble;

            if (iBubble.Title != null)
            {
                iBubble.Title.Text = e.NewValue as string;
            }
        }

        public string ProductTitleText
        {
            get { return GetValue(ProductTitleProperty) as string; }
            set { SetValue(ProductTitleProperty, value); }
        }

        #endregion

        #region Public Image Source Product Image

        public static readonly DependencyProperty ProductImageSourceProperty = DependencyProperty.Register(
            "ProductImageSource",
            typeof(ImageSource),
            typeof(InformationBubble),
            new PropertyMetadata(null, new PropertyChangedCallback(OnProductImageSourceChanged)));

        public static void OnProductImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            InformationBubble iBubble = sender as InformationBubble;

            if (iBubble.ProductImage != null)
            {
                iBubble.ProductImage.Source = e.NewValue as ImageSource;
            }
        }

        public ImageSource ProductImageSource
        {
            get { return GetValue(ProductImageSourceProperty) as ImageSource; }
            set { SetValue(ProductImageSourceProperty, value); }
        }

        #endregion

        public InformationBubble()
        {
             this.DefaultStyleKey = typeof(InformationBubble);
        }

        #region Overrides

        public override void OnApplyTemplate()
        {       
            base.OnApplyTemplate();

            Title = GetTemplateChild(InformationBubble.InformationBubbleTitlePart) as TextBlock;
            ProductImage = GetTemplateChild(InformationBubble.InformationBubbleProductImagePart) as Image;
        }

        #endregion

        #region Private Methods

        private void GoToState(string stateName, bool useTransitions)
        {
            VisualStateManager.GoToState(this, stateName, useTransitions);
        }

        #endregion
    }

Now if I use this control somewhere in my xaml it works if I do this:

<controls:InformationBubble 
        ProductImageSource="{Binding SelectedItem.NormalImageSource}"
        ProductTitleText="Test Title"
        "/>

But if I try and data bind the product title text to the title property of the SelectedItem object in my ViewModel:

<controls:InformationBubble 
            ProductImageSource="{Binding SelectedItem.NormalImageSource}"
            ProductTitleText="{Binding SelectedItem.Title, Mode=TwoWay"
            "/>

I get Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'. The text property of a TextBlock is a DependencyProperty so I must be missing something obvious here.


Solution

  • Could it be that the name of the property is wrong. Should the "ProductTitle" in the code below perhaps be "ProductTitleText"?

    public static readonly DependencyProperty ProductTitleProperty = DependencyProperty.Register(
        "ProductTitle",  // "ProductTitleText" ?
        typeof(string),
        typeof(InformationBubble),
        new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnProductTitleChanged)));
    

    I imagine that when you use a string constant, then WPF uses reflection to access the property "public string ProductTitleText" directly. The DependencyProperty is ignored, as the name of the property do not match ("ProductTitle" vs. "ProductTitleText").

    So for the title you have a dependency property called "ProductTitle" and a (string) property called "ProductTitleText". For the ProductImage you have a dependency property called "ProductImageSource" and a property (of type ImageSource) also called "ProductImageSource".

    Does it make sense?