473 lines
18 KiB
C#
473 lines
18 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Data;
|
||
using System.Windows.Documents;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using System.Windows.Media.Imaging;
|
||
using System.Windows.Navigation;
|
||
using System.Windows.Shapes;
|
||
using System.IO;
|
||
using System.Net.Sockets;
|
||
using System.Runtime.InteropServices;
|
||
|
||
namespace Marquee
|
||
{
|
||
/// <summary>
|
||
/// MainWindow.xaml 的互動邏輯
|
||
/// </summary>
|
||
public partial class MainWindow : Window
|
||
{
|
||
[DllImport("kernel32.dll")]
|
||
[return: MarshalAs(UnmanagedType.Bool)]
|
||
static extern bool AllocConsole();
|
||
|
||
private MainViewModel _viewModel;
|
||
|
||
public MainWindow()
|
||
{
|
||
InitializeComponent();
|
||
AllocConsole(); // 啟用控制台
|
||
Console.WriteLine("應用程式啟動");
|
||
_viewModel = new MainViewModel();
|
||
DataContext = _viewModel;
|
||
LoadRoomNumbers();
|
||
Console.WriteLine("初始化完成");
|
||
}
|
||
|
||
private void LoadRoomNumbers()
|
||
{
|
||
Console.WriteLine("開始載入房間號碼");
|
||
foreach (var room in _viewModel.RoomDictionary.Keys)
|
||
{
|
||
RoomNumbersComboBox.Items.Add(room);
|
||
Console.WriteLine($"已添加房間: {room}");
|
||
}
|
||
Console.WriteLine("房間號碼載入完成");
|
||
}
|
||
|
||
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
Console.WriteLine("TextBox1 Width: {0}", TextBox1.ActualWidth);
|
||
}
|
||
|
||
private void UpdateTextBox1()
|
||
{
|
||
string part1 = Marquee1ComboBox.SelectedItem?.ToString() ?? "";
|
||
string middle = TextBox3.Text.Trim();
|
||
string part3 = Marquee2ComboBox.SelectedItem?.ToString() ?? "";
|
||
|
||
TextBox1.Text = part1 + (string.IsNullOrEmpty(middle) ? "" : " " + middle + " ") + part3;
|
||
}
|
||
|
||
private void MarqueeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||
{
|
||
UpdateTextBox1(); // 更新 TextBox1 使用來自 ComboBox 和 TextBox3 的值
|
||
}
|
||
|
||
private void TextBox3_TextChanged(object sender, TextChangedEventArgs e)
|
||
{
|
||
UpdateTextBox1(); // 這同樣更新 TextBox1 當 TextBox3 的內容改變時
|
||
}
|
||
|
||
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
|
||
{
|
||
TextBox textBox = sender as TextBox;
|
||
double maxWidth = 480; // TextBox1的实际宽度
|
||
|
||
double pixelsPerDip = VisualTreeHelper.GetDpi(this).PixelsPerDip;
|
||
|
||
// 创建FormattedText以计算文本宽度
|
||
FormattedText formattedText = new FormattedText(
|
||
textBox.Text,
|
||
System.Globalization.CultureInfo.CurrentCulture,
|
||
FlowDirection.LeftToRight,
|
||
new Typeface(textBox.FontFamily, textBox.FontStyle, textBox.FontWeight, textBox.FontStretch),
|
||
textBox.FontSize,
|
||
Brushes.Black,
|
||
new NumberSubstitution(),
|
||
TextFormattingMode.Display,
|
||
pixelsPerDip); // 加入PixelsPerDip参数
|
||
|
||
// 检查文本渲染宽度是否超出TextBox的宽度
|
||
if (formattedText.Width > maxWidth)
|
||
{
|
||
// 找到能够在TextBox1中完全显示的最大文本长度
|
||
int maxFittingLength = 0;
|
||
for (int i = 1; i <= textBox.Text.Length; i++)
|
||
{
|
||
formattedText = new FormattedText(
|
||
textBox.Text.Substring(0, i),
|
||
System.Globalization.CultureInfo.CurrentCulture,
|
||
FlowDirection.LeftToRight,
|
||
new Typeface(textBox.FontFamily, textBox.FontStyle, textBox.FontWeight, textBox.FontStretch),
|
||
textBox.FontSize,
|
||
Brushes.Black,
|
||
new NumberSubstitution(),
|
||
TextFormattingMode.Display,
|
||
pixelsPerDip); // 加入PixelsPerDip参数
|
||
|
||
if (formattedText.Width > maxWidth)
|
||
{
|
||
maxFittingLength = i - 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 分割文本
|
||
if (maxFittingLength > 0)
|
||
{
|
||
TextBox2.Text = textBox.Text.Substring(maxFittingLength);
|
||
textBox.Text = textBox.Text.Substring(0, maxFittingLength);
|
||
}
|
||
else
|
||
{
|
||
// 如果maxFittingLength為0,清空TextBox2
|
||
TextBox2.Text = string.Empty;
|
||
}
|
||
}
|
||
}
|
||
|
||
private async void SendAnnouncement_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
Console.WriteLine("Triggered Send Announcement");
|
||
|
||
string marquee1Content = Marquee1ComboBox.SelectedItem?.ToString() ?? "";
|
||
string marquee2Content = Marquee2ComboBox.SelectedItem?.ToString() ?? "";
|
||
string announcement = $"{marquee1Content} {TextBox3.Text.Trim()} {marquee2Content}";
|
||
|
||
if (string.IsNullOrWhiteSpace(announcement))
|
||
{
|
||
System.Windows.MessageBox.Show("公告内容不能為空!");
|
||
return;
|
||
}
|
||
|
||
List<string> hostNames = new List<string>();
|
||
string selectedRoom = RoomNumbersComboBox.SelectedItem?.ToString();
|
||
|
||
if (!string.IsNullOrEmpty(selectedRoom))
|
||
{
|
||
if (selectedRoom == "全部")
|
||
{
|
||
// 獲取所有已占用的房間
|
||
var activeRooms = GetActiveRooms()
|
||
.Where(r => r.Status == "已占用")
|
||
.Select(r => r.PcName)
|
||
.ToList();
|
||
|
||
if (activeRooms.Any())
|
||
{
|
||
hostNames.AddRange(activeRooms);
|
||
}
|
||
else
|
||
{
|
||
System.Windows.MessageBox.Show("沒有找到任何已占用的房間!");
|
||
return;
|
||
}
|
||
}
|
||
else if (_viewModel.RoomDictionary.ContainsKey(selectedRoom))
|
||
{
|
||
hostNames.Add(_viewModel.RoomDictionary[selectedRoom]);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
System.Windows.MessageBox.Show("請選擇一個有效的房間號碼!");
|
||
return;
|
||
}
|
||
|
||
await Task.Run(async () =>
|
||
{
|
||
foreach (var hostName in hostNames)
|
||
{
|
||
await SendAnnouncementAsync(hostName, announcement);
|
||
}
|
||
}).ConfigureAwait(false);
|
||
}
|
||
|
||
private List<RoomState> GetActiveRooms()
|
||
{
|
||
Console.WriteLine("開始讀取活動房間狀態");
|
||
List<RoomState> roomStates = new List<RoomState>();
|
||
string filePath = @"C:\KTVAPP\roomstates.txt";
|
||
|
||
try
|
||
{
|
||
if (File.Exists(filePath))
|
||
{
|
||
string[] lines = File.ReadAllLines(filePath);
|
||
Console.WriteLine($"找到 {lines.Length} 條房間記錄");
|
||
foreach (string line in lines)
|
||
{
|
||
string[] parts = line.Split(';');
|
||
if (parts.Length >= 5)
|
||
{
|
||
var roomState = new RoomState
|
||
{
|
||
PcName = parts[0],
|
||
RoomNumber = parts[1],
|
||
Status = parts[2],
|
||
Time = parts[3],
|
||
ServiceStatus = parts[4]
|
||
};
|
||
roomStates.Add(roomState);
|
||
Console.WriteLine($"房間: {roomState.RoomNumber}, 狀態: {roomState.Status}, PC: {roomState.PcName}");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine($"找不到房間狀態文件: {filePath}");
|
||
LogToFile($"房間狀態文件不存在: {filePath}");
|
||
System.Windows.MessageBox.Show("找不到房間狀態文件!");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"讀取房間狀態文件失敗: {ex.Message}");
|
||
LogToFile($"讀取房間狀態文件失敗: {ex.Message}");
|
||
System.Windows.MessageBox.Show($"讀取房間狀態文件時發生錯誤:{ex.Message}");
|
||
}
|
||
|
||
Console.WriteLine($"總共找到 {roomStates.Count} 個房間,其中已占用的房間數: {roomStates.Count(r => r.Status == "已占用")}");
|
||
return roomStates;
|
||
}
|
||
|
||
private const int MaxSendAttempts = 3; // Maximum number of send attempts
|
||
private const int DelayBetweenSendAttempts = 1000; // Delay between send attempts in milliseconds
|
||
|
||
private async Task SendAnnouncementAsync(string hostname, string message)
|
||
{
|
||
int attemptCount = 0;
|
||
bool messageSent = false;
|
||
Exception lastException = null;
|
||
|
||
Console.WriteLine($"開始向 {hostname} 發送消息");
|
||
|
||
while (attemptCount < MaxSendAttempts && !messageSent)
|
||
{
|
||
try
|
||
{
|
||
using (TcpClient client = new TcpClient())
|
||
{
|
||
Console.WriteLine($"嘗試連接到 {hostname}... (第 {attemptCount + 1} 次嘗試)");
|
||
await client.ConnectAsync(hostname, 1000).ConfigureAwait(false);
|
||
using (NetworkStream stream = client.GetStream())
|
||
{
|
||
byte[] data = Encoding.UTF8.GetBytes(message + "\r\n");
|
||
await stream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
|
||
Console.WriteLine($"成功發送消息到 {hostname}");
|
||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||
System.Windows.MessageBox.Show($"成功發送消息到 {hostname}"));
|
||
messageSent = true;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"發送失敗 (第 {attemptCount + 1} 次嘗試): {ex.Message}");
|
||
LogToFile($"Error on send attempt {attemptCount + 1}: {ex.Message}");
|
||
lastException = ex;
|
||
}
|
||
|
||
attemptCount++;
|
||
if (!messageSent && attemptCount < MaxSendAttempts)
|
||
{
|
||
Console.WriteLine($"等待 {DelayBetweenSendAttempts}ms 後重試...");
|
||
await Task.Delay(DelayBetweenSendAttempts).ConfigureAwait(false);
|
||
}
|
||
}
|
||
|
||
if (!messageSent)
|
||
{
|
||
Console.WriteLine($"發送失敗,已達到最大重試次數 ({MaxSendAttempts})");
|
||
LogToFile($"Failed to send the announcement after multiple attempts. Last error: {lastException?.Message}");
|
||
}
|
||
}
|
||
|
||
private void LogToFile(string message)
|
||
{
|
||
string logFilePath = "log.txt"; // 设定日志文件的路径
|
||
string logMessage = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - {message}\r\n";
|
||
|
||
// 使用 File.AppendAllText 异步写入日志信息,它会自动创建文件(如果文件不存在的话)
|
||
File.AppendAllText(logFilePath, logMessage);
|
||
}
|
||
|
||
private void ToggleVisibility(object sender, RoutedEventArgs e)
|
||
{
|
||
if (SettingsGroupBox.Visibility == Visibility.Collapsed)
|
||
{
|
||
SettingsGroupBox.Visibility = Visibility.Visible;
|
||
this.Height = 660; // 調整窗口高度以容納GroupBox
|
||
}
|
||
else
|
||
{
|
||
SettingsGroupBox.Visibility = Visibility.Collapsed;
|
||
this.Height = 420; // 調整窗口高度回到較小尺寸
|
||
|
||
// 清空 ComboBox 的選擇
|
||
EditMarquee1ComboBox.SelectedItem = null;
|
||
EditMarquee2ComboBox.SelectedItem = null;
|
||
|
||
// 清空 TextBox 的文字
|
||
TextBoxForMarquee1.Text = "";
|
||
TextBoxForMarquee2.Text = "";
|
||
}
|
||
}
|
||
private void EditMarquee1ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||
{
|
||
// 確認是否有選中的項目
|
||
if (EditMarquee1ComboBox.SelectedItem != null)
|
||
{
|
||
TextBoxForMarquee1.Text = EditMarquee1ComboBox.SelectedItem.ToString();
|
||
}
|
||
}
|
||
private void DeleteMarquee1Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
if (EditMarquee1ComboBox.SelectedItem != null)
|
||
{
|
||
var itemToRemove = EditMarquee1ComboBox.SelectedItem.ToString();
|
||
|
||
// 直接操作绑定的数据源
|
||
((ObservableCollection<string>)EditMarquee1ComboBox.ItemsSource).Remove(itemToRemove);
|
||
|
||
// 清空相应的 TextBox 内容
|
||
TextBoxForMarquee1.Clear();
|
||
|
||
// 从文件中移除
|
||
RemoveItemFromMarqueeFile(itemToRemove, @"txt\marquee1_items.txt");
|
||
}
|
||
}
|
||
|
||
// 處理新增按鈕點擊事件
|
||
private void AddMarquee1Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
var newItem = TextBoxForMarquee1.Text;
|
||
|
||
if (!string.IsNullOrEmpty(newItem))
|
||
{
|
||
var items = (ObservableCollection<string>)EditMarquee1ComboBox.ItemsSource;
|
||
|
||
if (!items.Contains(newItem))
|
||
{
|
||
items.Add(newItem);
|
||
|
||
// 添加到文件
|
||
AddItemToMarqueeFile(newItem, @"txt\marquee1_items.txt");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void EditMarquee2ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||
{
|
||
var viewModel = (MainViewModel)DataContext;
|
||
if (EditMarquee2ComboBox.SelectedItem != null && viewModel.SelectedMarquee2Item != EditMarquee2ComboBox.SelectedItem.ToString())
|
||
{
|
||
viewModel.SelectedMarquee2Item = EditMarquee2ComboBox.SelectedItem.ToString();
|
||
}
|
||
}
|
||
|
||
private void DeleteMarquee2Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
if (EditMarquee2ComboBox.SelectedItem != null)
|
||
{
|
||
var itemToRemove = EditMarquee2ComboBox.SelectedItem.ToString();
|
||
|
||
// 直接操作绑定的数据源
|
||
((ObservableCollection<string>)EditMarquee2ComboBox.ItemsSource).Remove(itemToRemove);
|
||
|
||
// 清空相应的 TextBox 内容
|
||
TextBoxForMarquee2.Clear();
|
||
|
||
// 从文件中移除
|
||
RemoveItemFromMarqueeFile(itemToRemove, @"txt\marquee2_items.txt");
|
||
}
|
||
}
|
||
|
||
private void TextBoxForMarquee2_TextChanged(object sender, TextChangedEventArgs e)
|
||
{
|
||
var viewModel = (MainViewModel)DataContext;
|
||
var textBox = sender as TextBox;
|
||
//if (textBox != null && textBox.Text != viewModel.TextBoxForMarquee2)
|
||
if (textBox != null)
|
||
{
|
||
Console.WriteLine(textBox.Text);
|
||
// 更新 ViewModel 中的 TextBoxForMarquee2 属性
|
||
if (viewModel.TextBoxForMarquee2 != textBox.Text)
|
||
{
|
||
viewModel.TextBoxForMarquee2 = textBox.Text;
|
||
Console.WriteLine("TextBoxForMarquee2 Updated: " + textBox.Text);
|
||
viewModel.OnPropertyChanged(nameof(viewModel.TextBoxForMarquee2)); // 手动触发 PropertyChanged
|
||
}
|
||
|
||
// 更新 ComboBox 的 SelectedItem
|
||
if (viewModel.SelectedMarquee2Item != textBox.Text)
|
||
{
|
||
viewModel.SelectedMarquee2Item = textBox.Text;
|
||
Console.WriteLine("SelectedMarquee2Item Updated: " + textBox.Text);
|
||
viewModel.OnPropertyChanged(nameof(viewModel.SelectedMarquee2Item)); // 手动触发 PropertyChanged
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine("TextBox is null"); // 确认 sender 被正确转换
|
||
}
|
||
}
|
||
|
||
private void RemoveItemFromMarqueeFile(string item, string filePath)
|
||
{
|
||
var lines = File.ReadAllLines(filePath).ToList();
|
||
bool itemFound = false;
|
||
|
||
for (int i = 0; i < lines.Count; i++)
|
||
{
|
||
if (lines[i].Contains(item))
|
||
{
|
||
lines.RemoveAt(i); // 删除整行
|
||
itemFound = true;
|
||
break; // 假设每个项目只出现一次,找到即删除
|
||
}
|
||
}
|
||
|
||
if (itemFound)
|
||
{
|
||
File.WriteAllLines(filePath, lines);
|
||
}
|
||
}
|
||
|
||
// 處理新增按鈕點擊事件
|
||
private void AddMarquee2Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
var newItem = TextBoxForMarquee2.Text;
|
||
|
||
if (!string.IsNullOrEmpty(newItem))
|
||
{
|
||
var items = (ObservableCollection<string>)EditMarquee2ComboBox.ItemsSource;
|
||
|
||
if (!items.Contains(newItem))
|
||
{
|
||
items.Add(newItem);
|
||
|
||
// 添加到文件
|
||
AddItemToMarqueeFile(newItem, @"txt\marquee2_items.txt");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void AddItemToMarqueeFile(string item, string filePath)
|
||
{
|
||
using (StreamWriter sw = File.AppendText(filePath))
|
||
{
|
||
sw.WriteLine(item);
|
||
}
|
||
}
|
||
}
|
||
}
|