4

I want to bind a TextBlock to a string which takes its value from a txt file. The string is correctly filled but its contents are not displayed.

Class file:

public partial class JokesMessageBox : Window
    {
        public JokesMessageBox()
        {
            InitializeComponent();
        }

        public string Joke { get; set; }
        public string path = "data/jokes.txt";

        public void ReadFile(string path)
        {
            Joke = File.ReadAllText(path);
        }
    }

XAML:

<TextBlock HorizontalAlignment="Left" Margin="22,10,0,0"
 TextWrapping="Wrap" Text="{Binding Joke}" VerticalAlignment="Top"
 Height="60" Width="309"/>

EDIT:

In the MainWindow class:

 private void btnJokesFirstScreen_Click_1(object sender, RoutedEventArgs e)
        {
  JokesMessageBox jkb = new JokesMessageBox();
                jkb.Show();
                jkb.ReadFile("data/jokes.txt");
        }

I spent 3+ hours on google, youtube, MSDN, StackOverflow and still can't get it working. What am I missing?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Bruno
  • 59
  • 1
  • 1
  • 6

3 Answers3

10

If the you need to update the binding, the property Joke must be a DependencyProperty or the Windows must implement INotifyPropertyChanged interface.

On the view, the binding needs to know Source.

Example #1 (Using DependencyProperty):

public partial class JokesMessageBox : Window
{
    public JokesMessageBox()
    {
        InitializeComponent();

        ReadFile(Path); //example call
    }

    public string Joke
    {
        get { return (string)GetValue(JokeProperty); }
        set { SetValue(JokeProperty, value); }
    }

    public static readonly DependencyProperty JokeProperty =
        DependencyProperty.Register("Joke", typeof(string), typeof(JokesMessageBox), new PropertyMetadata(null));


    public const string Path = "data/jokes.txt";

    public void ReadFile(string path)
    {
        Joke = File.ReadAllText(path);
    }
}

Example #2 (Using INotifyPropertyChanged interface):

public partial class JokesMessageBox : Window, INotifyPropertyChanged
{
    public JokesMessageBox()
    {
        InitializeComponent();

        ReadFile(Path); //example call
    }

    private string _joke;

    public string Joke
    {
        get { return _joke; }
        set
        {
            if (string.Equals(value, _joke))
                return;
            _joke = value;
            OnPropertyChanged("Joke");
        }
    }

    public const string Path = "data/jokes.txt";

    public void ReadFile(string path)
    {
        Joke = File.ReadAllText(path);
    }


    //INotifyPropertyChanged members
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

And the view (XAML partial):

...
<TextBlock HorizontalAlignment="Left" Margin="22,10,0,0"
    TextWrapping="Wrap" 
    Text="{Binding Joke,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" 
    VerticalAlignment="Top"
    Height="60" Width="309"/>
...

I hope it helps.

denys-vega
  • 3,522
  • 1
  • 19
  • 24
  • This worked! I went with the second example. After I had read this: [link](http://stackoverflow.com/questions/1995325/bind-wpf-textblock-to-text-file) I thought it would be something quick and easy. Now I looked at the other similar problems other people had posted and I noticed this INotifyPropertyChanged interface. I'll look into it. Thanks! – Bruno Mar 26 '15 at 23:15
0

When you read the contents of the file, you assign the read string to your Joke property:

Joke = File.ReadAllText(path);

The Text property of the TextBlock is indeed bound to that property (if you have properly set the data context):

Text="{Binding Joke}"

However, what is missing is that the binding cannot possibly have any idea that the property value has changed. You need to issue a notification about the property change.

There are two ways to do this that will be recognized by WPF bindings:

  • You declare your Joke property as a dependency property. This is based on some WPF infrastructure that automatically issues the change notifications.
  • You have your class implement the INotifyPropertyChanged interface. Here, you have to implement a simple interface with a PropertyChanged event, which you have to fire in your property setter while passing the name of the property as a string.
O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
0

Your class is not implementing INotifyPropertyChanged interface. So when you change property Joke TextBlock is not updated. I would do something like this:

public partial class JokesMessageBox : Window, INotifyPropertyChanged
    {
        public JokesMessageBox()
        {
            InitializeComponent();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public string Joke { get; set; }
        public string path = "data/jokes.txt";

        public void ReadFile(string path)
        {
            Joke = File.ReadAllText(path);
            OnPropertyChanged("Joke");
        }

        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

I would also suggest you to read about MVVM patern.

Ivan Vasiljevic
  • 5,478
  • 2
  • 30
  • 35