Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从异步操作调用时,如何从STA线程更新窗口控件?_C#_Wpf_Multithreading - Fatal编程技术网

C# 从异步操作调用时,如何从STA线程更新窗口控件?

C# 从异步操作调用时,如何从STA线程更新窗口控件?,c#,wpf,multithreading,C#,Wpf,Multithreading,我的服务器应用程序是一个WPF项目,它使用异步回调来处理客户端请求并将响应发送回客户端 服务器将根据从客户端接收的数据更新其数据库,并根据数据的性质,通过其自己的UI推送警报以反映新警报 当需要更新UI时,我得到一个错误,即调用线程必须是STA线程或类似的东西 如何确保尝试更新UI的线程已正确设置为在不导致错误的情况下进行更新 下面是我所有的代码和关于代码的注释 客户助手 ClientHelper类是客户端请求的包装器 public class ClientHelper { privat

我的服务器应用程序是一个WPF项目,它使用异步回调来处理客户端请求并将响应发送回客户端

服务器将根据从客户端接收的数据更新其数据库,并根据数据的性质,通过其自己的UI推送警报以反映新警报

当需要更新UI时,我得到一个错误,即调用线程必须是STA线程或类似的东西

如何确保尝试更新UI的线程已正确设置为在不导致错误的情况下进行更新

下面是我所有的代码和关于代码的注释

客户助手 ClientHelper类是客户端请求的包装器

public class ClientHelper
{
    private readonly TcpClient _Client;
    private readonly byte[] _Buffer;

    public Client(TcpClient client)
    {
        _Client = client;
        int BufferSize = _Client.ReceiveBufferSize;
        _Buffer = new byte[BufferSize];
    }

    public TcpClient TcpClient
    {
        get { return _Client; }
    }
    public byte[] Buffer
    {
        get { return _Buffer; }
    }
    public NetworkStream NetworkStream
    {
        get { return TcpClient.GetStream(); }
    }
}
FooServer 服务器使用在其自身线程上运行的TcpListener,以避免锁定UI

public class FooServer
{
    private TcpListener Svr;

    public void StartServer()
    {
        Thread ListenerThread = new Thread(new ThreadStart(() =>
        {
            Svr = new TcpListener(IPAddress.Parse("127.0.0.1"), 13000);
            Svr.Start();

            Svr.BeginAcceptTcpClient(AcceptClientCallback, null);
        }));
        ListenerThread.SetApartmentState(ApartmentState.STA);
        ListenerThread.IsBackground = true;

        ListenerThread.Start();
    }  
服务器通过维护其连接的客户端列表来跟踪这些客户端

    private List<Client> ConnectedClients = new List<Client>();
    private void AcceptClientCallback(IAsyncResult result)
    {
        TcpClient Client;
        try
        {
            Client = Svr.EndAcceptTcpClient(result);
        }
        catch (Exception ex)
        {
            OnError(Svr, ex);
            //Svr.Stop();
            return;
        }

        Svr.BeginAcceptTcpClient(AcceptClientCallback, null);

        ClientHelper _Client = new ClientHelper(Client);
        ConnectedClients.Add(_Client);
        NetworkStream Stream = _Client.NetworkStream;
        Stream.BeginRead(_Client.Buffer, 0, _Client.Buffer.Length, ReadCallback, _Client);
    }
EvaluateFooData
根据可接受的标准检查客户数据,并将任何偏差添加到列表中,该列表由下面的
AddAlert
读取,该列表将警报添加到数据库中

public void AddAlert()
{
    ApplicationDbContext Context = new ApplicationDbContext();

    foreach (Alert Alert in Alerts)
    {
        Context.Alerts.Add(Alert);
    }
    Context.SaveChanges();

    OnRaiseAlert();
}

public event EventHandler RaiseAlert;
protected virtual void OnRaiseAlert()
{
    RaiseAlert?.Invoke(this, null);
}
使用在UI上注册的EventHandler,服务器将警报推送到UI:

public MainWindow()
{
    InitializeComponent();

    Server.RaiseAlert += Server_RaiseAlert;
}
private void Server_RaiseAlert(object sender, EventArgs e)
{
    ApplicationDbContext Context = new ApplicationDbContext();
    var Alerts = Context.Alerts.Where(x => x.IsResolved == false).ToList();

    StackPanel FooStackPanel = new StackPanel();
    spFoo.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { FooStackPanel = spFoo; }));

    if (Alerts != null && Alerts.Count >= 1)
    {
        foreach (Alert Alert in Alerts)
        {
            Button Btn = (Button)FooStackPanel.Children[FooId];
            Btn.Style = FindResource("FooAlertIcon") as Style;
        }
    }
}

Server\u RaiseAlert
通过更改窗口初始化期间创建的按钮样式来更新UI,以便这些按钮现在指示该Foo存在问题。基本概念是绿色=好,红色=坏。

在Dispatcher操作中处理UI元素的所有操作:

private void Server_RaiseAlert(object sender, EventArgs e)
{
    var context = new ApplicationDbContext();
    var alerts = context.Alerts.Where(x => x.IsResolved == false).ToList();

    if (alerts.Count > 0)
    {
        spFoo.Dispatcher.Invoke(new Action(() =>
        {
            foreach (var alert in alerts)
            {
                var button = (Button)spFoo.Children[FooId];
                button.Style = FindResource("FooAlertIcon") as Style;
            }
        }));
    }
}

但是请注意,从您的问题中不清楚
FooId
来自何处。

您必须更具体地说明错误。哪一个错误,在哪一行?STA线程必须有一个消息泵,我在您创建的线程中看不到消息泵。
请注意,从您的问题中不清楚FooId来自何处。
这不是问题。只是我的粘贴不完整,先生,你应该得到更多,而不仅仅是对这个答案投一张有用的票。我不能告诉你我有多激动,因为它现在可以工作了!非常感谢你。
private void Server_RaiseAlert(object sender, EventArgs e)
{
    var context = new ApplicationDbContext();
    var alerts = context.Alerts.Where(x => x.IsResolved == false).ToList();

    if (alerts.Count > 0)
    {
        spFoo.Dispatcher.Invoke(new Action(() =>
        {
            foreach (var alert in alerts)
            {
                var button = (Button)spFoo.Children[FooId];
                button.Style = FindResource("FooAlertIcon") as Style;
            }
        }));
    }
}