0

Hi Guys I'm trying to dynamically update a textblock by reading a value over TCP/IP. What am I doing wrong and how can I solve it? Also if there is a better way to do things I'm opening to learning.

Here I'm using a public static to use this class in other classes.

I've now implemented INotifyPropertyChanged and added the binding but its still not working as expected, what am I do

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Script_Launcher.Validation
{
    //Global variable to read message elsewhere in the code.
    public class Message
    {
        private static string message = "";

        public static string Messager
        {
            get { return message; }
            set { message = value; }

        }
    }
} 

Here I'm opening a exe which is acting as the client and sends data to my server.

using HandyControl.Data;
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Script_Launcher.Validation;
using System.Threading.Tasks;

namespace Script_Launcher.Views
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        TcpListener server;
        TcpClient clientconnection;

        private void ListBoxItem_Selected_1(object sender, RoutedEventArgs e)
        {
            

            foreach (var process in Process.GetProcessesByName("OSP_Analysis"))
            {
                process.Kill();
            }

            Process.Start(@"C:\Users\path\OSP_Analysis");

            Task.Run(() =>
            {
                //Vars
                //TcpListener server;
                //TcpClient clientconnection;

                server = new TcpListener(IPAddress.Parse("127.0.0.1"), 8088); //Opens Server on said port
                server.Start(); //Starts listener
                Trace.WriteLine("Server started...");
                clientconnection = server.AcceptTcpClient(); //Accepts Request

                NetworkStream DataStream = clientconnection.GetStream(); //Gets data stream
                byte[] buffer = new byte[clientconnection.ReceiveBufferSize];
                int Data = DataStream.Read(buffer, 0, clientconnection.ReceiveBufferSize); //Recieves data (encoded)
                Message.Messager = Encoding.ASCII.GetString(buffer, 0, Data); //Decodes data (python .encode() function uses the ASCII code)

                clientconnection.Close();
                server.Server.Close();
            });

        }
    }
}

Trying to use comparisons to update the textblock

using System.Net.Sockets;
using System.Net;
using System.Text;
using System;
using System.Windows.Controls;
using System.Diagnostics;
using System.Threading;
using System.Drawing.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows;
using static Script_Launcher.Views.OilPerformance;
using System.Runtime.Remoting.Messaging;
using System.Windows.Media;
using Script_Launcher.Validation;

namespace Script_Launcher.Views
{
    /// <summary>
    /// Interaction logic for OilPerformance
    /// </summary>
    public partial class OilPerformance : UserControl
    {
        public OilPerformance()
        {
            InitializeComponent();

            string message = Message.Messager;
            Trace.WriteLine(message);

            if (message == "1500")
            {
                PASSFAIL.Text = "PASS!";
                PASSFAIL.Foreground = new SolidColorBrush(Colors.Green);
            }
            else if (message == "1501")
            {
                PASSFAIL.Text = "FAIL!";
                PASSFAIL.Foreground = new SolidColorBrush(Colors.Red);
            }
            else
            {
                PASSFAIL.Text = "WAITING...";
                PASSFAIL.Foreground = new SolidColorBrush(Colors.Orange);
            }
        }
    }

}

Finally the XAML

<UserControl x:Class="Script_Launcher.Views.OilPerformance"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/" 
             xmlns:hc="https://handyorg.github.io/handycontrol"
             prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <Grid Margin="20" Background="{DynamicResource RegionBrush}">
        </Grid>

        <Grid Margin="40" VerticalAlignment="Center" HorizontalAlignment="Center">
            <StackPanel Margin="32,64,32,32" VerticalAlignment="Center">
            <TextBlock x:Name="PASSFAIL" Margin="0,15,0,-15" FontSize="72"></TextBlock>
            </StackPanel>
        </Grid>
    </Grid>
</UserControl>

I've now implemented INotifyPropertyChanged.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;

namespace Script_Launcher.Validation
{
    class MessageClone : ObservableObject
    {
        private string messageclone = Message.Messager;

        public string Messageclone

        {

            get { return messageclone; }
            set
            {
                messageclone = value;
                OnPropertyChanged("Messageclone");
            }
        }

        public MessageClone()
        {
            Task.Run(() =>
            {
                while(true)
                {
                    if (messageclone == "1500")
                    {
                        Messageclone = "PASS!";
                        //PASSFAIL.Foreground = new SolidColorBrush(Colors.Green);
                    }
                    else if (messageclone == "1501")
                    {
                        Messageclone = "FAIL!";
                        //PASSFAIL.Foreground = new SolidColorBrush(Colors.Red);
                    }
                    else
                    {
                        Messageclone = "WAITING...";
                        //Messageclone.Foreground = new SolidColorBrush(Colors.Orange);
                        //this.Messageclone.Background = new SolidColorBrush(Colors.Orange);
                        Thread.Sleep(1000);
                        Trace.WriteLine(messageclone);
                    }
                }

            });

            
        }

        
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Script_Launcher.Validation
{
    class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged? .Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
        private MessageClone messageclone;
        
        public OilPerformance()
        {
            InitializeComponent();

            this.DataContext = messageclone = new MessageClone();
The Jargen
  • 21
  • 3
  • Does this answer your question? [Textblock binding not working in WPF](https://stackoverflow.com/questions/27231196/textblock-binding-not-working-in-wpf) – Rekshino Mar 16 '23 at 10:04
  • No, unless I'm missing something... I need a more descriptive answer. – The Jargen Mar 16 '23 at 16:11
  • You are missing MVVM concept, binding to the property and implementation of INotifyPropertyChanged in the viewmodel. – Rekshino Mar 16 '23 at 19:52
  • I've now implemented INotifyPropertyChanged but its still not working as expected. By printing my string with trace.writeline only see the else statement. Please help. – The Jargen Mar 17 '23 at 10:18
  • So where are you setting the `Messageclone` to anything else than "WAITING..."...? – mm8 Mar 22 '23 at 13:02

2 Answers2

0

Bind the TextBlock to the source property that you are setting in the loop on the background thread:

<TextBlock x:Name="PASSFAIL" Text="{Binding Messageclone}" Margin="0,15,0,-15" FontSize="72" />
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thanks I did implement the binding, but only the else case is evaluated for some reason. As a result my textblock only says waiting. Not sure what to do next... – The Jargen Mar 17 '23 at 21:53
0

You must call directly OnPropertyChanged if you want to notify changes.

By calling method like bellow, you can change the value and call OnPropertyChanged at the same time.

protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
}
private string _test;
public string Test
{
    get => _test;
    set => SetField(ref _test, value);
}
Segel
  • 22
  • 1
  • 5
  • The setter of the `Messageclone` property already raises the `PropertyChanged` event through the base class. – mm8 Mar 17 '23 at 12:08