none
Custom Class not binding as expected

    Question

  • I have a custom Class full of properties that use "INotifyPropertyChanged" but binding is not working as expected.

    Here is my Custom Class:

    public class RuntimeValues : INotifyPropertyChanged
        {
            private String _Name = null;
            String _ID = null;
    
            public String ID
            {
                get { return _ID; }
                set {
                    if (value != _ID)
                    {
                        _ID = value;
                        RaisePropertyChanged("ID");
                    }
                }
            }
    
            public String Name
            {
                get { return _Name; }
                set {
                    if (value != _Name)
                    {
                        _Name = value;
                        RaisePropertyChanged("Name");
                    }
                }
            }
    
            public Boolean hasValidUser
            {
                get { return !String.IsNullOrEmpty(ID) && !String.IsNullOrEmpty(Name); }
            }
    
            #region NotifiyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void RaisePropertyChanged(String PropertyName)
            {
                PropertyChangedEventHandler currentHandler = PropertyChanged;
    
                if (currentHandler != null)
                    currentHandler(this, new PropertyChangedEventArgs(PropertyName));
    
            }
            #endregion
        }

    Here is a converter, that should show an Error String instead of nothing:

    public class NameToLabel : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if(value == null || String.IsNullOrEmpty((string)value))
                    return "No Name Stored";
    
                return value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

    My Windows Xaml Code includes the two things above in the "ST" XAML-namespace, the window looks shortened like this:

    ...Window>
    
    <Window.Resources>
            <ST:RuntimeValues x:Name="RV" x:Key="RuntimeValues"></ST:RuntimeValues>
            <ST:NameToLabel x:Key="NTLCovnerter"/>
        </Window.Resources>
    
    <Menu DockPanel.Dock="Top">
                <Label Content="{Binding Path=Name, ElementName=RV, Converter={StaticResource NTLCovnerter}}"></Label>
                <MenuItem Command="Properties"></MenuItem>
            </Menu>
    
    </Window>

    The designer is, as expected, is showing me "No Name Stored" or whatever I set the Name attribute to:

    <ST:RuntimeValues x:Name="RV" x:Key="RuntimeValues" Name="Test"></ST:RuntimeValues>

    But when I run this Programm, I just get some label sized emptyness where the Name or "No Name Stroed" string should be shown.

    So, what am I doing wrong here?

    Tuesday, March 13, 2012 10:36 AM

Answers

  • Hi Christopher,

    maybe I'm wrong but I think "ElementName=" references to a named control not to a static resource. Turn on error mode for binding in the VS environment in order to check whether your binding can be resolved. If you would really like to point to a resource, you should use "Source=" as far as I know.

    Greetings,
    Chris

    Tuesday, March 13, 2012 11:26 AM
  • Sorry, forgot to mark as answer. I have meanwhile put my data/converter into the app.xaml:
    <Application.Resources>
            <SPEC:RuntimeValues x:Key="RuntimeValues" ></SPEC:RuntimeValues>
            <SPEC:NameToLabel x:Key="NTLCovnerter"/>
    </Application.Resources>

    And rewritten the bindings as following:
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="{Binding Path=Name, 
    Converter={StaticResource NTLCovnerter}, 
    Source={StaticResource RuntimeValues}}"/>
                <MenuItem Command="Properties"/>
            </Menu>

    I've also set the Options -> Debugging -> Output Window -> Databinding setting to All, wich as far as I understand is the highest setting:
    http://msdn.microsoft.com/en-us/library/dd794543.aspx


    Thursday, March 15, 2012 8:41 AM

All replies

  • Hi,

    To use the static resource with the converter the following statement should work.

     <Label Content="{Binding Source={StaticResource ResourceKey=runtimeValues}, 
                Converter={StaticResource ResourceKey=NTLCovnerter}, 
                ConverterParameter=Name}"></Label>

    And the converter should be like this.

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
          {
             if (value == null)
                return "No Name Stored";
             if (parameter.ToString() == "Name")
                return ((RuntimeValues)value).Name;
    
             return value;
          }

    This is sample hack. Hope this gives some idea to deal with the issue.

    /Srinivas

    Tuesday, March 13, 2012 11:25 AM
  • Hi Christopher,

    maybe I'm wrong but I think "ElementName=" references to a named control not to a static resource. Turn on error mode for binding in the VS environment in order to check whether your binding can be resolved. If you would really like to point to a resource, you should use "Source=" as far as I know.

    Greetings,
    Chris

    Tuesday, March 13, 2012 11:26 AM
  • Hi Christopher,

    maybe I'm wrong but I think "ElementName=" references to a named control not to a static resource. Turn on error mode for binding in the VS environment in order to check whether your binding can be resolved. If you would really like to point to a resource, you should use "Source=" as far as I know.

    Greetings,
    Chris

    I'd love to turn those error messages on, but I have no idea where they hid the option. Do you have any idea?

    But with your help I did find a way to circumvent the problem:

    <Menu DockPanel.Dock="Top" DataContext="{DynamicResource ResourceKey=RuntimeValues}">
                <Label Content="{Binding Path=Name, Converter={StaticResource ResourceKey=NTLCovnerter}}"></Label>
                <MenuItem Command="Properties"></MenuItem>
            </Menu>
    Tuesday, March 13, 2012 11:57 AM
  • Hi Christopher.

    Are you sure you want this as a static reference?

    PropertyChanged events won't work for static objects.

    If you plan to update the values during the lifetime of the page, you won't see the changes reflected in the UI.

    Also, the converter doesn't need to pass the object and extract a property based on parameter. The parameter is usually used for other aspects of a converter, not extracting a property from the class as a whole. Normally you just bind the property you want to convert.

        

    Below is a tested, working version of your code, using a dynamically generated object that can be updated.
    I've even added a button to show dynamic changing and updating.

         

    <Window
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	x:Class="WpfApplication75.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="640" Height="480" WindowStartupLocation="CenterScreen" xmlns:local="clr-namespace:WpfApplication75">
        <Window.Resources>
            <local:NameToLabel x:Key="NTLCovnerter"/>
        </Window.Resources>
    
        <StackPanel>
            <Menu DockPanel.Dock="Top">
                <Label Content="{Binding Path=runtimeValues.Name}" />
                <MenuItem Command="Properties"></MenuItem>
            </Menu>
            <Button Click="Button_Click" Content="Test Dynamic" HorizontalAlignment="Left"/>
        </StackPanel>
        
    </Window>

         

    using System.Windows;
    using System.Windows.Data;
    using System;
    using System.ComponentModel;
    
    namespace WpfApplication75
    {
        public partial class MainWindow : Window, INotifyPropertyChanged
        {
            public RuntimeValues runtimeValues { get; set; }
    
            public MainWindow()
            {
                InitializeComponent();
                runtimeValues = new RuntimeValues();
                DataContext = this;
            }
    
            void RaisePropertyChanged(string prop)
            {
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                runtimeValues.Name = "Changed";
            }
        }
    
        public class NameToLabel : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null)
                    return "No Name Stored";
    
                return parameter.ToString();
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    
     

      

    Hope that helps,
    Pete


    #PEJL

    Tuesday, March 13, 2012 12:24 PM
    Moderator
  • Hi Christopher.

    Are you sure you want this as a static reference?

    PropertyChanged events won't work for static objects.

    If you plan to update the values during the lifetime of the page, you won't see the changes reflected in the UI.

    Well, that is funny. Because for me propertyChanged and StaticResources DO work perfectly and always have been.

    The difference between Static and Dynamic has nothing to do with Binding in general. They do differentiate, once I try to set the Resource itself during runtime (after the first binding is evaluated). Wich is something you normally don't do at all.

    A Static binding won't notice/expect that the object behind the resource has been changed and propably still reference the old one.
    A dynamic Binding will detect/be informed by the Resource Dictionary that the instance behind the Key "runtimeValues" has changed, and thus bindings should be re-evlauted (with the new instance as the source).

    For my situation I will really need DynamicBinding, but for other reasons. And even without, this:

    <Window.Resources>
            <ST:RuntimeValues x:Key="RuntimeValues" Name="Test"></ST:RuntimeValues>
            <ST:NameToLabel x:Key="NTLCovnerter"/>
        </Window.Resources>
    
    <Menu DockPanel.Dock="Top" DataContext="{StaticResource ResourceKey=RuntimeValues}">
                <MenuItem Header="{Binding Path=Name, Converter={StaticResource ResourceKey=NTLCovnerter}}"></MenuItem>
                <MenuItem Command="Properties"></MenuItem>
            </Menu>
    Works perfectly with this code:
    ((RuntimeValues) this.Resources["RuntimeValues"]).ID = "1";
                ((RuntimeValues)this.Resources["RuntimeValues"]).Name = "Hans";
    Tuesday, March 13, 2012 1:18 PM
  • Hi Christopher,

    I use the german environment, so my description might only give you a hint. I can switch on binding error messages by opening the options dialog of VS 2010. Then, select the entry "Debug" or "Debugging" on the left side. Under this entry you will find something like "output window". Seelct this entry. In the property list on the right side you can find entry like "Binding". Here, you can select the level of output for data binding.

    Greetings,
    Chris

    Wednesday, March 14, 2012 6:14 AM
  • Hi Christopher,

    I use the german environment,

    As do I. 

    I set it to All, but couldn't figure out how to produce any error with it as I have strongly modified my build again.

    In my earleir seaarch I found this, but did not test it:
    http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors

    And suddenly the Binding assistant is able to use this one as Static Resource again (earlier for some reason it always told me the resource was there twice when I selected it. Even if I set the name to something like "asdhash").

    Wednesday, March 14, 2012 8:54 AM
  • Versuche es mit "Error" als Einstellung. Funktioniert bei mir am Besten.

    Viele Grüße
    Christoph

    Wednesday, March 14, 2012 2:12 PM
  • Hi Christopher84,

    I think set your datasource to DataContext is the correct method, and then you could set binding as you want, becasue the binding.Path property will get the data source from DataContext property.

    DataContext="{StaticResource RuntimeValues}"

    I think you have got the solution of the binding issue, as for your last concern about error message on binding, I suggest you read this article:

    http://bea.stollnitz.com/blog/?p=52

    there are many method included, "output window", "empty Converter", "System.Diagnostics", those method are helpful for you, if you want to set the Output window setting in VS, refer to:

    Additional, if you want to check the value of Label.content, i suggest you learn more about WPF validation, it will be better.

    Best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, March 15, 2012 7:27 AM
    Moderator
  • Sorry, forgot to mark as answer. I have meanwhile put my data/converter into the app.xaml:
    <Application.Resources>
            <SPEC:RuntimeValues x:Key="RuntimeValues" ></SPEC:RuntimeValues>
            <SPEC:NameToLabel x:Key="NTLCovnerter"/>
    </Application.Resources>

    And rewritten the bindings as following:
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="{Binding Path=Name, 
    Converter={StaticResource NTLCovnerter}, 
    Source={StaticResource RuntimeValues}}"/>
                <MenuItem Command="Properties"/>
            </Menu>

    I've also set the Options -> Debugging -> Output Window -> Databinding setting to All, wich as far as I understand is the highest setting:
    http://msdn.microsoft.com/en-us/library/dd794543.aspx


    Thursday, March 15, 2012 8:41 AM