11 Replies - 5285 Views - Last Post: 23 February 2012 - 06:21 AM Rate Topic: -----

#1 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Binding to code behind property mystery

Posted 21 February 2012 - 04:41 PM

So often when writing up a question I find what I am doing wrong. Its amazing what you find when you have to explain it to others and don't want to look like a dummy. This is not one of those times. I'm trying to do more in WPF to learn it but it is still kicking my but at unexpected times.

The idea is fairly simple:
Main program made up of various UserControls.
Each UserControl has a class instances for its preferences. Thus the preferences are serializable.
WPF UserControl has TextBoxes on it with bindinds set to the code-behind properties, which get;set; to the settings object class.

Here's where it gets odd:
If the code-behind file uses a local field for the property the binding to the WPF control works.
If the code-behind file uses a property in the preferences object the binding doesn't seem to work.

Let me walk you through it:
Open the application and you have the menu on the left, and the workspace on the right is blank.
Click the Email button and the EmailSettingsDLG UserControl is made, populated and placed in the right side workspace.
Here's the code doing that:
Spoiler


Attached Image


Notice that the only TextBox that is populated is for the FromAddress and contains "Clint"

Looking at the code-behind for the window we can see the only difference between the FromAddress and the FromPassword properties is that one uses a local string field and one uses an object string property.

These breakpoints are being hit. They do confirm the values.

Attached Image


Attached Image


The XAML for the window:

Spoiler



As near as I can see everything is coded and binding set in exactly the same way, no typos etc.

So does WPF not work for binding to object properties? How is one supposed to serialize data objects used by GUI's then? I read a LOT that data binding is one of the strong points of shifting to WPF and that binding to GUI controls like this is one of the things lots of people do. So WTF am I doing wrong?

The only thing I can think of is that the preferences class instance is being made from the MainWindow code, and thus the MainWindow thread. And so even though execution is getting and setting these values they fail when binding to the UserControl textboxes. I do this sort of thing all the time in WinForms without a problem. Is there a way to do this in WPF?

Is This A Good Question/Topic? 1
  • +

Replies To: Binding to code behind property mystery

#2 janne_panne  Icon User is offline

  • WinRT Dev
  • member icon

Reputation: 429
  • View blog
  • Posts: 1,047
  • Joined: 09-June 09

Re: Binding to code behind property mystery

Posted 22 February 2012 - 02:28 AM

I can't notice anything being wrong in your code. But I wrote a small sample and it seems to work so I'll post the code here and perhaps you notice something being different.

UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" 
			 DataContext="{Binding RelativeSource={RelativeSource Self}}" >
	<Grid>
		<Grid.RowDefinitions>
			<RowDefinition Height="auto" />
			<RowDefinition Height="auto" />
			<RowDefinition Height="auto" />
		</Grid.RowDefinitions>
		<TextBox Text="{Binding Path=Age, Mode=TwoWay}" Grid.Row="0" />
		<TextBox Text="{Binding Path=UserName, Mode=TwoWay}" Grid.Row="1" />
		<TextBox Text="{Binding Path=Address, Mode=TwoWay}" Grid.Row="2" />
	</Grid>
</UserControl>



UserControl1.xaml.cs + User class
    public partial class UserControl1 : UserControl, System.ComponentModel.INotifyPropertyChanged
    {
        public UserControl1()
        {
            this.User = new User();
            InitializeComponent();
        }

        private User User { get; set; }

        public int Age
        {
            get { return this.User.Age; }
            set
            {
                this.User.Age = value;
                this.onpropertychanged("Age");
            }
        }

        public string UserName
        {
            get { return this.User.Name; }
            set
            {
                this.User.Name = value;
                this.onpropertychanged("UserName");
            }
        }

        public string Address
        {
            get { return this.User.Address; }
            set
            {
                this.User.Address = value;
                this.onpropertychanged("Address");
            }
        }

        protected void onpropertychanged(string str)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(str));
        }

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    }

    class User
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
    }



Mainwindow.xaml.cs (just a window with one grid and one button):
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var ctrl = new UserControl1();
            this.grid.Children.Add(ctrl);
            ctrl.Age = 100;
            ctrl.UserName = "hello";
            ctrl.Address = "world";
        }

        private int counter = 1;

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            var ctrl = (from child in this.grid.Children.Cast<UIElement>()
                        where child is UserControl1
                        select child).FirstOrDefault() as UserControl1;
            if (ctrl != null)
            {
                ctrl.UserName = "hello" + counter.ToString();
                ctrl.Address = "world" + counter.ToString();
                ctrl.Age += counter;
                counter++;
            }
        }
    }



Another thing you could do is expose the EmailPreferences class as a public property and bind directly to it like this: <TextBox Text="{Binding Path=EmailPreferences.SMTPaddress, Mode=TwoWay}" Grid.Row="0" /> But then your EmailPreferences has to implement INotifyPropertyChanged to update values in UI.
Was This Post Helpful? 2
  • +
  • -

#3 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,960
  • Joined: 21-March 08

Re: Binding to code behind property mystery

Posted 22 February 2012 - 06:02 AM

Is EmailPreferences a static class? or is it an object on the UserControl? Can you show where it's initialized?
Was This Post Helpful? 0
  • +
  • -

#4 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Re: Binding to code behind property mystery

Posted 22 February 2012 - 06:12 AM

Its not static. Its an instance of a class.

Attached Image

Since Janne was able to do a project to test this, and that worked, then its something I did or am not doing that is causing this. Which is what I figured it had to be but can't find. I'll make a new project and work Janne's example into it then see what I'm doing differently or wrong.

Must. Make. Frappicino.

Maybe a fresh look at it after a night's sleep will prove helpful.

This post has been edited by tlhIn`toq: 22 February 2012 - 06:49 AM

Was This Post Helpful? 0
  • +
  • -

#5 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Re: Binding to code behind property mystery

Posted 22 February 2012 - 07:00 AM

UPDATE: I have confirmed that Janne's test project works as expected on my machine. Thank you very much for that! At least I can stop doubting the validity of the concept and go back to doubting my own skill and sanity.
Was This Post Helpful? 0
  • +
  • -

#6 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Re: Binding to code behind property mystery

Posted 22 February 2012 - 07:39 AM

So I changed my object from a field to a property to match Janne's example. Makes sense since you need the propertychanged event. Duh, I should have realized that. Then it got strange again.
It comes up as null. Yet it is being set in the constructor. How can it possibly be null under these conditions?

Object being created in the window's constructor

Attached Image


Yet coming up null right after when trying to access its properties. Whiskey Tango Foxtrot?

Attached Image


Its this sort of simple stuff that is supposed to be a no-brainer that totally breaks my brain when it doesn't work. And eats days for no reason that seems reasonable when you try to log it on your time sheet.
Was This Post Helpful? 0
  • +
  • -

#7 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Re: Binding to code behind property mystery

Posted 22 February 2012 - 07:54 AM

Ok. That was my fault. I had initializeCompent() before making the object. Rookie mistake.

Still not having the rest work though. But tracking it down with the help of caffeine.
Was This Post Helpful? 0
  • +
  • -

#8 janne_panne  Icon User is offline

  • WinRT Dev
  • member icon

Reputation: 429
  • View blog
  • Posts: 1,047
  • Joined: 09-June 09

Re: Binding to code behind property mystery

Posted 22 February 2012 - 08:24 AM

It's a good sign it's crashing in get methods, the bindings should work then. Could there be something wrong it UI styles? Something as wild as the foreground of textboxes is white (you set foreground only for one textbox)? Or some other display problem for textboxes.
Was This Post Helpful? 2
  • +
  • -

#9 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,838
  • Joined: 02-June 10

Re: Binding to code behind property mystery

Posted 22 February 2012 - 09:07 AM

That was it. Thank you!!!!

Spoiler


Oh my fraking %&^%%$ %&%^% ^^&5 !@%$#%^^

Are you kidding me? The default color combination for textboxes is white on white? I never set that. I just dragged them out. I changed the FromAddress box because I wanted to give it a URL-esque look of blue, underlined, monospaced (CRISP.tt font). Coming from WinForms where the default is black on white it just never occured to me that the default would be white on white. Well that's a lesson I'll only have to learn once.

3 days I have agonized over this. How stupid do I now look and feel?!

Talk about having egg on my face!
Attached Image
Was This Post Helpful? 0
  • +
  • -

#10 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,960
  • Joined: 21-March 08

Re: Binding to code behind property mystery

Posted 22 February 2012 - 01:21 PM

No, the default Foreground color is not White. As you can see in your screenshot, the "black diamond" means that it's being set by something(you can hover over it to see where the source is coming from).

Here is what it looks like normally.

Attached Image
Was This Post Helpful? 1
  • +
  • -

#11 The Architect 2.0  Icon User is offline

  • D.I.C Regular

Reputation: 37
  • View blog
  • Posts: 351
  • Joined: 22-May 08

Re: Binding to code behind property mystery

Posted 23 February 2012 - 04:13 AM

I know this issue is resolved, but I'm having a similiar problem in my application as well. I'm not as smart as tlhIn`toq so I don't quite understand why the User object needs to be a property.

In my situation, I am using List<> properties in the 'User'/model object and ObservableCollections in 'UserControl'/viewmodel. Both collections use custom objects as well as strings.

I'm going to try this code change out as well once i figure out how to do it without collapsing the whole program, but if someone could explain the technical part to me, I'd appreciate it.
Was This Post Helpful? 0
  • +
  • -

#12 eclipsed4utoo  Icon User is offline

  • Not Your Ordinary Programmer
  • member icon

Reputation: 1524
  • View blog
  • Posts: 5,960
  • Joined: 21-March 08

Re: Binding to code behind property mystery

Posted 23 February 2012 - 06:21 AM

If I am not mistaken, his real problem was the Foreground Color was White, so I looked like the data wasn't getting bound.

Just to be sure, I did an example that shows that it is possible to bind the way that tlhIn`toq was trying.

Very simple...

Mainwindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private EmailPreferences prefs = new EmailPreferences();
    List<string> emails = new List<string>();
    int count = 0;

    public string FromAddress
    {
        get
        {
            return prefs.FromEmail;
        }
        set
        {
            if (value != prefs.FromEmail)
            {
                prefs.FromEmail = value;
                onpropertychanged("FromAddress");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void onpropertychanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        emails.Add("testing@test.com");
        emails.Add("yes@yesnetwork.com");
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        count++;

        if (count % 2 == 0)
            FromAddress = emails[0];
        else
            FromAddress = emails[1];
    }
}



Mainwindow.xaml
<Window
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cust="clr-namespace:WpfApplication1"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="MainWindow"
    Height="350"
    Width="525">

    <Grid>

        <TextBox
            Height="23"
            Text="{Binding Path=FromAddress, Mode=TwoWay}"
            HorizontalAlignment="Left"
            Margin="180,88,0,0"
            Name="textBox2"
            VerticalAlignment="Top"
            Width="120" />

        <Button
            Content="Button"
            Height="23"
            HorizontalAlignment="Left"
            Margin="202,180,0,0"
            Name="button1"
            VerticalAlignment="Top"
            Width="75"
            Click="button1_Click" />
    </Grid>
</Window>



This example simply switches the text that's in the textbox when clicking a button.

If you have a specific issue, you can open a new topic and post your code and the problems you are having.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1