Marquee/MainWindow.xaml.cs
2025-03-19 10:22:21 +08:00

473 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}
}