很抱歉创建了另一个主题,因为我的问题并不具体,也不准确导致该帖子被关闭和删除。
我有一个聊天应用程序,我希望我的应用程序不会挂起,而聊天对话的文本块每秒刷新一次以检索当前对话。如何防止我的应用程序不停止并每秒恢复? 我实际上使用谷歌但作为回报我没有找到具体的答案。 这是我的代码:
public MainWindow()
{
InitializeComponent();
timerChatRefresh = new DispatcherTimer();
timerChatRefresh.Interval = new TimeSpan(0, 0, 1);
timerChatRefresh.IsEnabled = false;
timerChatRefresh.Tick += new EventHandler(timerChatRefresh_Tick);
timerChatRefresh.Start();
}
void timerChatRefresh_Tick(object sender, EventArgs e)
{
ChatRefresh();
}
private void ChatRefresh()
{
conn = new MySqlConnection("Server=...; Database=...; Uid=...; Password=...;");
ds.Clear();
textBlockChatArea.Text = "";
da.SelectCommand = conn.CreateCommand();
da.SelectCommand.CommandText = "select * from chatmessagetbl";
da.SelectCommand.CommandType = CommandType.Text;
da.Fill(ds, "chatmessagetbl");
foreach (DataRow item in ds.Tables["chatmessagetbl"].Rows)
{
textBlockChatArea.Text += item["username"].ToString() + ": " + item["message"].ToString() + "\n";
}
conn.Dispose();
}
答案 0 :(得分:2)
尝试将并行任务用作后台工作程序或线程
答案 1 :(得分:2)
您需要更新非UI线程的线程上的文本框。
Thread chatRefreshTimer;
void StartChat()
{
chatRefreshTimer = new Thread(new ThreadStart(ChatRefresh));
chatRefreshTimer.Start();
}
void ChatRefresh()
{
conn = new MySqlConnection("Server=...; Database=...; Uid=...; Password=...;");
ds.Clear();
da.SelectCommand = conn.CreateCommand();
da.SelectCommand.CommandText = "select * from chatmessagetbl";
da.SelectCommand.CommandType = CommandType.Text;
while (true)
{
da.Fill(ds, "chatmessagetbl");
textBlockChatArea.Text = "";
foreach (DataRow item in ds.Tables["chatmessagetbl"].Rows)
{
//This has to be done on the thread that owns the textbox.
textBlockChatArea.Dispatcher.BeginInvoke(new Action(() =>
{
textBlockChatArea.Text += item["username"].ToString() + ": " + item["message"].ToString() + "\n";
}));
}
Thread.Sleep(TimeSpan.FromSeconds(1));
}
conn.Dispose();
}
我提供的代码不是很干净,它并不意味着你可以复制和粘贴的最终解决方案(虽然它可能会起作用),它只是试图帮助你朝着正确的方向前进,向您展示可以通过线程完成的一种方式。
修改强>
为了尝试清除我在评论中使用列表控件而不是文本框的观点,我添加了以下伪程序来尝试解释我的意思。
// Each row returned from the database will be converted in to one of these.
public class ChatEntry
{
public string UserName { get; set; }
public string Message { get; set; }
public int MessageID { get; set; }
}
// You will need to introduce a MessageID field to your database to make this method work.
public partial class MainWindow : Window
{
public ObservableCollection<ChatEntry> Entries
{
get { return (ObservableCollection<ChatEntry>)GetValue(EntriesProperty); }
set { SetValue(EntriesProperty, value); }
}
public static readonly DependencyProperty EntriesProperty = DependencyProperty.Register("Entries", typeof(ObservableCollection<ChatEntry>), typeof(MainWindow), new UIPropertyMetadata(null));
// This will be used to make sure that only new entries are added to the chat log.
int lastMessageID;
// This will be used to call UpdateEntries every second.
Thread updateThread;
public MainWindow()
{
Entries = new ObservableCollection<ChatEntry>();
InitializeComponent();
updateThread = new Thread(new ThreadStart(UpdateEntries));
updateThread.Start();
}
void UpdateEntries()
{
while (true)
{
// Prepare your query to gather messages from the message table
// with MessageID > lastMessageID.
// This bit needs to be done on the UI dispatcher or it'll cause an exception.
this.Dispatcher.BeginInvoke(new Action(() =>
{
// Each row that came back is a new message and can be added to the collection.
foreach (var row in rows)
{
Entries.Add(new ChatEntry()
{
UserName = (string)row["UserName"],
Message = (string)row["Message"],
});
}
}));
// at this point, the UI will have been upadted with JUST the new entries, no flicker
// no scrolling to the top each second.
// just one more thing, we need to set lastMessageID to be the latest messageID
// so next time UpdateEntries is called it'll only get the new ones that we don't
// have yet.
lastMessageID = Entries.Max(x => x.MessageID);
// Sleep for a second to ease the update speed.
Thread.Sleep(1000);
}
}
}
要将列表框绑定到新的Entries属性,您可以在XAML中执行类似的操作。
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<ListView ItemsSource="{Binding Entries}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0,0,5,0" FontWeight="Bold" />
<TextBlock Text="{Binding Message}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Window>