Update Textblock value dynamically (Update)

69 views Asked by At

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();
2

There are 2 answers

1
mm8 On

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" />
1
Segel On

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);
}