Marquee/MainWindow.xaml.cs

473 lines
18 KiB
C#
Raw Permalink Normal View History

2025-03-19 10:22:21 +08:00
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);
}
}
}
}