wpf TextBlock中的文本不会更改

6fe3ivhb  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(133)

我有两个程序:客户端(使用WPF)和服务器(控制台应用程序)。服务器可以使用两个线程。客户端向服务器发送“1”或“2”,然后服务器向其发送“3”或“4”。客户端成功获取答案,但由于线程的原因,TextBlock中显示“1”或“2”(过时)。变量“result”始终为“\0”,客户端中的“PropertyChanged”始终为null。
伺服器:

using System.Text;
using System.Net.Sockets;
using System.Net;

namespace Server
{
    internal class ServerHandler
    {
        //private const string _IP = "127.0.0.1";
        private const int _PORT = 8888;
        private const int _BUFFER_SIZE = 1;
        protected internal TcpListener _Listener { get; set; }

        protected internal async Task ListenAsync()
        {
            try
            {
                //IPAddress localAddr = IPAddress.Parse(_IP);
                _Listener = new TcpListener(IPAddress.Any, _PORT);
                _Listener.Start();

                while (true)
                {
                    Console.WriteLine("oK");
                    TcpClient tcpClient = await _Listener.AcceptTcpClientAsync();
                    ClientObject clientObject = new ClientObject(tcpClient);
                }

                //ClientHandler(_Listener.AcceptTcpClient());
            }
            catch (SocketException ex)
            {
                throw new Exception(ex.Message);
            }
        }

        ~ServerHandler()
        {
            if (_Listener != null)
                _Listener.Stop();
        }

        static void Main(string[] args)
        {
            try
            {
                ServerHandler handler = new();
                handler.ListenAsync();
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        internal class ClientObject
        {
            protected internal TcpClient _Client { get; set; }
            protected internal NetworkStream _Stream { get; set; }
            public ClientObject(TcpClient client)
            {
                _Client = client;
                byte[] buffer = new byte[_BUFFER_SIZE];
                _Stream = _Client.GetStream();
                _Stream.BeginRead(buffer, 0, buffer.Length, EndRead, buffer);
                //_Stream.ReadAsync(buffer, 0, buffer.Length);
                //_Stream.Write(buffer, 0, buffer.Length);

                string result = Encoding.UTF8.GetString(buffer);
                //_Stream.WriteAsync(buffer);

                SendMessage(result);
            }

            public void EndRead(IAsyncResult result)
            {
                byte[] buffer = (byte[])result.AsyncState;
                var ns = _Client.GetStream();
                var bytesAvalable = ns.EndRead(result);
            }

            async void SendMessage(string str)
            {
                try
                {
                    //await Task.Run(() =>
                    //{
                        int val;
                        bool isParsed = Int32.TryParse(str, out val);

                        if (!isParsed)
                            return;

                        if (val != 1 && val != 2)
                            return;

                        val = val == 1 ? 3 : 4;

                        str = val.ToString();
                        byte[] buffer = Encoding.UTF8.GetBytes(str);
                        _Stream.WriteAsync(buffer);
                        _Stream.Flush();
                    //});
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

字符串
Client.xaml:

<Window x:Class="Client.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Client"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="300">
    <Grid>
        <Button x:Name="Button_1" Content="Send" FontSize="15" Width="100" Height="30" Margin="180, 10, 0, 160"
            Click="Button_Click" ClickMode="Press">
        </Button>

        <TextBox x:Name="TextBox_1" MaxLength="50" FontSize="15" Margin="10, 20, 120, 170" TextChanged="TextBox_TextChanged">
        </TextBox>

        <TextBlock x:Name="TextBlock_1" TextWrapping="Wrap" Margin="10, 90, 10, 100" Text="{Binding Message, Mode=TwoWay}" OpacityMask="#00000000" Background="#FF685959">
        </TextBlock>
    </Grid>
</Window>


Client.xaml.cs:

using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Net.Sockets;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Client
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private const string _IP = "127.0.0.1";
        private const int _PORT = 8888;
        private const int _BUFFER_SIZE = 1;
        private TcpClient _Client;
        private string _message;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            try
            {
                TextBox textBox = (TextBox)sender;
                textBox.MaxLength = 1;
                int numVal;
                bool isParsed = int.TryParse(textBox.Text, out numVal);

                if (isParsed)
                {
                    if (numVal != 1 && numVal != 2)
                        TextBlock_1.Text = "The value must be 1 or 2!";
                    else
                        TextBlock_1.Text = String.Empty;
                }
                else
                {
                    TextBlock_1.Text = "The value must be 1 or 2!";
                }
            }
            catch (Exception ex)
            {
                TextBlock_1.Text = ex.Message;
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _Client = new TcpClient();

            try
            {
                int numVal;
                bool isParsed = int.TryParse(TextBox_1.Text, out numVal);

                if (!isParsed)
                    return;

                if (numVal != 1 && numVal != 2)
                    return;

                _Client.ConnectAsync(_IP, _PORT);

                // Error
                var Stream = _Client.GetStream();

                if (Stream != null && TextBox_1.Text != String.Empty)
                {
                    byte[] buffer = new byte[_BUFFER_SIZE];
                    buffer = Encoding.UTF8.GetBytes(TextBox_1.Text);
                    SendMessage(Stream, buffer);
                    byte[] bufferResult = new byte[_BUFFER_SIZE];

                    Stream.BeginRead(bufferResult, 0, bufferResult.Length, EndRead, bufferResult);
                    string result = Encoding.UTF8.GetString(bufferResult);

                    //Binding binding = BindingOperations.GetBinding(TextBlock_1, TextBlock.TextProperty);
                    Message = result;

                }
            }
            catch (SocketException ex)
            {
                TextBlock_1.Text = ex.Message;
            }
        }

        public void EndRead(IAsyncResult result)
        {
            byte[] buffer = (byte[])result.AsyncState;
            var ns = _Client.GetStream();
            var bytesAvalable = ns.EndRead(result);
        }

        public void BeginRead(TcpClient Client)
        {
            try
            {
                if (Client == null)
                    return;

                byte[] buffer = new byte[_BUFFER_SIZE];
                
                if (Client.Connected)
                {
                    NetworkStream Stream = Client.GetStream();
                    AsyncCallback callback = null;
                    callback = ar =>
                    {
                        Stream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
                    };
                }
                else
                {
                    Client.Connect(_IP, _PORT);
                }
                
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        async void SendMessage(NetworkStream Stream, byte[] buffer)
        {
            try
            {
                Stream.Write(buffer, 0, buffer.Length);
                string result = Encoding.UTF8.GetString(buffer);
                Stream.Flush();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #region ViewModelProperty: Message
        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                //_message = value;
                _message = "123";
                OnPropertyChanged(_message);
            }
        }
        #endregion

        #region INotifiedProperty Block
        //public event EventHandler SomeEventHappened = delegate { };
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            try
            {
                PropertyChangedEventHandler handler = PropertyChanged;

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                //handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
            catch (Exception ex) { }
        }
        #endregion
    }
}


最初,我试图使用“TextBlock_1.Text = result”,但它不起作用,值仍然是“1”和“2”。然后我读到我需要使用PropertyChangedEventEvent事件。但它没有帮助。

vybvopom

vybvopom1#

这需要正确的INotifyPropertyChanged实现。这意味着每次属性更改时,都需要以Properties名称作为内容触发PropertyChanged事件。在public string Message的实现中,您使用值而不是属性名称。
所以用途:

public string Message
    {
        get
        {
            return _message;
        }
        set
        {
            //_message = value;
            _message = "123";
            OnPropertyChanged();// No parameter or "Message" as parameter
        }
    }

字符串
您的接口实现是正确的,如果方法在没有参数的情况下被调用,使用[CallerMemberName]将自动插入属性名称:

public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        try
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            //handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        catch (Exception ex) { }
    }

相关问题