0

I'm making a basic program where a label updates when the user types in a text box. i'm trying to use data binding and INotifyPropertyChanged to work this out, so i don't want any workarounds. i used 2 buttons so i can actually see if they updated. here's my main class

namespace TestStringChangeFromAnotherClass

public partial class MainWindow : Window
{

    textClass someTextClass = new textClass();
    public MainWindow()
    {

        InitializeComponent();

    }

    public string someString1;
    public string someString2;

    private void btn1_Click(object sender, RoutedEventArgs e)
    {
        someTextClass.Text1 = tbx1.Text;
    }

    private void btn2_Click(object sender, RoutedEventArgs e)
    {
        someTextClass.Text2 = tbx1.Text;
    }
}

here's the wpf for it

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

    <Grid>
    <Button x:Name="btn1" Content="Button" HorizontalAlignment="Left" Height="36" Margin="29,246,0,0" VerticalAlignment="Top" Width="108" Click="btn1_Click"/>
    <Button x:Name="btn2" Content="Button" HorizontalAlignment="Left" Height="36" Margin="227,246,0,0" VerticalAlignment="Top" Width="124" Click="btn2_Click"/>
    <Label x:Name="lbl1" Content="{Binding textClass.Text1}" HorizontalAlignment="Left" Height="37" Margin="74,32,0,0" VerticalAlignment="Top" Width="153"/>
    <Label x:Name="lbl2" Content="{Binding textClass.Text2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="38" Margin="74,90,0,0" VerticalAlignment="Top" Width="153"/>
    <TextBox x:Name="tbx1" HorizontalAlignment="Left" Height="37" Margin="290,32,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="190"/>

</Grid>

as you can see, i've tried using UpdateSourceTrigger. i've also tried to use "someTestClass.Text1" instead of textClass.Test1, because that's how i defined it in the MainWindow. Here's my textClass

namespace TestStringChangeFromAnotherClass
public class textClass:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string text1;
    public string Text1
    {
        get { return text1; }
        set
        {
            text1 = value;
            NotifyPropertyChanged("Text1");
        }
    }

    private string text2;
    public string Text2
    {
        get { return text2; }
        set
        {
            text2 = value;
            NotifyPropertyChanged("Text2");
        }
    }

    protected void NotifyPropertyChanged(string info)
    {

        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

i can't figure out how to get wpf to look for the Test1 or Test2 strings in the separate class and update them when the strings change. i have a feeling the problem lies within DataContext, but i can't figure it out. i'd also rather not use DataContext within c#, only in WPF

UPDATE: when i debug this, when it gets to NotifyPropertyChanged, PropertyChanged is evaluated as null. could that be the problem?

darthwillard
  • 809
  • 2
  • 14
  • 28
  • Have you tried implementing INotifyPropertyChanged in Mainwindow too? Since this is your datacontext. – TylerD87 Jan 23 '14 at 15:46
  • if i add INotifyPropertyChanged in the MainWindow, i get this error -'TestStringChangeFromAnotherClass.MainWindow' does not implement interface member 'System.ComponentModel.INotifyPropertyChanged.PropertyChanged' – darthwillard Jan 23 '14 at 16:13
  • maybe, what i need to do is try to get the UpdateSourceTrigger to look at the PropertyChanged item in the textClass class? – darthwillard Jan 23 '14 at 16:15

2 Answers2

1

You bind DataContext to your Window which, as far as I can see, doesn't have textClass property. It has someTextClass field of textClass type. In order for your code to work your can change someTextClass to public property:

public textClass someTextClass { get; private set; }

initialize it in constructor:

public MainWindow()
{
    someTextClass = new textClass();
    InitializeComponent();

}

and then change binding to point to someTextClass property

<Label x:Name="lbl1" Content="{Binding someTextClass.Text1}" .../>
<Label x:Name="lbl2" Content="{Binding someTextClass.Text2}" .../>
dkozl
  • 32,814
  • 8
  • 87
  • 89
  • moved the initialization into the constructor and changed the binding properties, also changed all the properties to public, doesn't work – darthwillard Jan 23 '14 at 16:19
  • Is your code exactly like in my example? I've tried this code before I posted an answer and it worked fine – dkozl Jan 23 '14 at 16:24
  • works now. weird. i had it initialize after InitializeComponent. i have to initialize it before InitializeComponent? why is that? and what does the "get; private set;" do? – darthwillard Jan 23 '14 at 16:29
  • That is correct and it's because `someTextClass` property does not notify when it's changed so it must available before your bindings are created. `get; private set;` means that getter has same visibility as property, so public, and setter is private so can be set only from within `MainWindow` class – dkozl Jan 23 '14 at 16:32
  • is there a more appropriate way to do this? Thanks a million, also, i've been at this for the last 5 hours!! – darthwillard Jan 23 '14 at 16:33
  • This is one way but normally I would remove `someTextClass` property altogether, set `DataContext = new textClass();`(instead of `DataContext` binding in Mainwindow.xaml) change bindings to `Content="{Binding Text1}"`, bind `tbx1.Text` to something else and basically let view create itself/react based on bindings and changes to view model. Read more about MVVM pattern. – dkozl Jan 23 '14 at 16:47
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45931/discussion-between-darthwillard-and-dkozl) – darthwillard Jan 23 '14 at 16:51
0

You are binding to the MainWindow class itself as your DataContext, and trying to access the property called someTextClass that has the properties you want to bind to.

You are running into two problems:

1) Your XAML is trying to reference the desired object by it's type, not it's name. Not going to work. Your binding expressions should look like {Binding someTextClass.Text1} (note the difference in the first part of the path expression).

2) You can only bind to public things. Your field is not defined as public, and therefore is private. Even though the XAML should logically "be able to see" the property, as it's the same class, DataBinding will only work on public properties.

3) EDIT: You must also make this a property. WPF will not bind to fields.

In general, using Snoop will help diagnose silent binding errors.

Clever Neologism
  • 1,322
  • 8
  • 9
  • 1. i changed it the binding to that, not working. 2. i changed everything private to public. that didn't work either. 3. not sure what you mean here? – darthwillard Jan 23 '14 at 16:18
  • Instead of `textClass someTextClass = new textClass();`, instead use `public textClass someTextClass {get; private set;}` and in your constructor, add `someTextClass = new textClass();` [What is the difference between a field and a property in C#?](http://stackoverflow.com/questions/295104/what-is-the-difference-between-a-field-and-a-property-in-c) may be helpful to explain further about fields and properties. – Clever Neologism Jan 23 '14 at 17:56