feat: Utils 클래스 추가

prototype
HyungJune Kim 7 months ago
parent af88b6e5a3
commit f4304373b1

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmartAquaViewer.Classes
{
class Constants
{
public const string CONFIG_INI = "config.ini";
public class Config
{
public const string CONFIG = "CONFIG";
public const string TITLE = "TITLE";
public const string DATA_FILE_PATH = "DATA-FILE-PATH";
public const string REC_PATH = "REC-PATH";
}
public class Directories
{
public const string DATA_FOLDER = "data_folder";
public const string REC_FOLDER = "REC";
}
}
}

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartAquaViewer.INI;
namespace SmartAquaViewer.Classes
{
class Utils
{
public static Utils Instance { get; } = new Utils();
public readonly string CurrentDirectory = Environment.CurrentDirectory;
private static INIManager? iniManager;
public static INIManager IniManager
{
get
{
if (iniManager == null)
{
string iniPath = Path.Combine(Instance.CurrentDirectory, Constants.CONFIG_INI);
iniManager = new INIManager(iniPath);
}
return iniManager;
}
}
private string GetGeneralSection(String strKey, String? defaultValue)
{
return IniManager.ReadValue(Constants.Config.CONFIG, strKey, defaultValue);
}
private void WriteValue(String strKey, String value)
{
IniManager.WriteValue(Constants.Config.CONFIG, strKey, value);
}
private string? title;
private string Title
{
get
{
if (title == null)
{
title = GetGeneralSection(Constants.Config.TITLE, null);
}
return title;
}
}
public string GetTitle()
{
return Title;
}
private string? dataFilePath;
private string DataFilePath
{
get
{
if (dataFilePath == null)
{
dataFilePath = GetGeneralSection(Constants.Config.DATA_FILE_PATH, null);
}
return dataFilePath;
}
}
public string GetDataFilePath()
{
return DataFilePath;
}
public void CreateDirectory(string folderName)
{
string directoryPath = Path.Combine(Environment.CurrentDirectory, folderName);
if (Directory.Exists(directoryPath))
return;
Directory.CreateDirectory(directoryPath);
Console.WriteLine($"Directory created at: {directoryPath}");
}
public void DebugWriteLine(string value, params object[] args)
{
if (Debugger.IsAttached)
{
Debug.WriteLine(value, args);
FileLog(value);
}
}
public void WriteFileLog(object value)
{
File.AppendAllText(Path.Combine(CurrentDirectory, "log.txt"), String.Format("[{0}]\n{1}\n", DateTime.Now.ToString("yyyy-MM-dd HH:MM:ss"), value), Encoding.Default);
}
public void FileLog(object value)
{
WriteFileLog(value);
}
}
}

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading;
using SmartAquaViewer.ViewModel; using SmartAquaViewer.ViewModel;
namespace SmartAquaViewer.Helper namespace SmartAquaViewer.Helper
@ -20,6 +22,13 @@ namespace SmartAquaViewer.Helper
public static void SetEnable(DependencyObject d, bool v) => d.SetValue(EnableProperty, v); public static void SetEnable(DependencyObject d, bool v) => d.SetValue(EnableProperty, v);
public static bool GetEnable(DependencyObject d) => (bool)d.GetValue(EnableProperty); public static bool GetEnable(DependencyObject d) => (bool)d.GetValue(EnableProperty);
public static readonly DependencyProperty SuspendProperty =
DependencyProperty.RegisterAttached("Suspend", typeof(bool), typeof(DataGridAutoPageSizeBehavior),
new PropertyMetadata(false));
public static void SetSuspend(DependencyObject d, bool v) => d.SetValue(SuspendProperty, v);
public static bool GetSuspend(DependencyObject d) => (bool)d.GetValue(SuspendProperty);
// 🔹 여기! 어느 페이저를 갱신할지 바인딩으로 지정 // 🔹 여기! 어느 페이저를 갱신할지 바인딩으로 지정
public static readonly DependencyProperty PagerProperty = public static readonly DependencyProperty PagerProperty =
DependencyProperty.RegisterAttached( DependencyProperty.RegisterAttached(
@ -29,15 +38,45 @@ namespace SmartAquaViewer.Helper
public static void SetPager(DependencyObject d, IPager? v) => d.SetValue(PagerProperty, v); public static void SetPager(DependencyObject d, IPager? v) => d.SetValue(PagerProperty, v);
public static IPager? GetPager(DependencyObject d) => (IPager?)d.GetValue(PagerProperty); public static IPager? GetPager(DependencyObject d) => (IPager?)d.GetValue(PagerProperty);
public static readonly DependencyProperty ThrottleMsProperty =
DependencyProperty.RegisterAttached("ThrottleMs", typeof(int), typeof(DataGridAutoPageSizeBehavior),
new PropertyMetadata(120));
public static void SetThrottleMs(DependencyObject d, int v) => d.SetValue(ThrottleMsProperty, v);
public static int GetThrottleMs(DependencyObject d) => (int)d.GetValue(ThrottleMsProperty);
private static readonly ConditionalWeakTable<DataGrid, DispatcherTimer> _timers = new();
private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
if (d is DataGrid dg) if (d is not DataGrid dg) return;
if ((bool)e.NewValue)
{ {
if ((bool)e.NewValue) dg.SizeChanged += DataGrid_SizeChanged; dg.SizeChanged += DataGrid_SizeChanged;
else dg.SizeChanged -= DataGrid_SizeChanged; EnsureTimer(dg);
}
else
{
dg.SizeChanged -= DataGrid_SizeChanged;
if (_timers.TryGetValue(dg, out var t))
{
t.Stop();
_timers.Remove(dg);
}
} }
} }
private static void EnsureTimer(DataGrid dg)
{
if (_timers.TryGetValue(dg, out _)) return;
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(GetThrottleMs(dg)) };
timer.Tick += (_, __) =>
{
timer.Stop();
ApplyAutoPageSize(dg);
};
_timers.Add(dg, timer);
}
private static void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e) private static void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{ {
if (sender is not DataGrid dg) return; if (sender is not DataGrid dg) return;
@ -57,6 +96,21 @@ namespace SmartAquaViewer.Helper
if (pager.PageSize != rows) if (pager.PageSize != rows)
pager.PageSize = rows; // 페이저 쪽에서 RebuildPage() 호출됨 pager.PageSize = rows; // 페이저 쪽에서 RebuildPage() 호출됨
} }
}
private static void ApplyAutoPageSize(DataGrid dg)
{
if (GetSuspend(dg)) return; // 여기도 방어
if (dg.RowHeight <= 0 || dg.ActualHeight <= 0) return;
double header = dg.ColumnHeaderHeight > 0 ? dg.ColumnHeaderHeight : 30;
double available = Math.Max(0, dg.ActualHeight - header - 2);
int rows = Math.Max(1, (int)(available / dg.RowHeight));
IPager? pager = GetPager(dg) ?? dg.DataContext as IPager;
if (pager is null) return;
if (pager.PageSize != rows)
pager.PageSize = rows; // 내부에서 RebuildPage() 호출
}
}
} }

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using SmartAquaViewer.Classes;
namespace SmartAquaViewer.INI
{
class EmbeddedAssembly
{
static Dictionary<string, Assembly> dic = null;
/// <summary>
/// Load Assembly, DLL from Embedded Resources into memory.
/// </summary>
/// <param name="embeddedResource">Embedded Resource string. Example: WindowsFormsApplication1.SomeTools.dll</param>
/// <param name="fileName">File Name. Example: SomeTools.dll</param>
public static void Load(string embeddedResource, string fileName)
{
if (dic == null)
dic = new Dictionary<string, Assembly>();
byte[] ba = null;
Assembly asm = null;
Assembly curAsm = Assembly.GetExecutingAssembly();
using (Stream stm = curAsm.GetManifestResourceStream(embeddedResource))
{
// Either the file is not existed or it is not mark as embedded resource
if (stm == null)
throw new Exception(embeddedResource + " is not found in Embedded Resources.");
// Get byte[] from the file from embedded resource
ba = new byte[(int)stm.Length];
stm.Read(ba, 0, (int)stm.Length);
try
{
asm = Assembly.Load(ba);
// Add the assembly/dll into dictionary
dic.Add(asm.FullName, asm);
return;
}
catch
{
// Purposely do nothing
// Unmanaged dll or assembly cannot be loaded directly from byte[]
// Let the process fall through for next part
}
}
bool fileOk = false;
string tempFile = "";
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
// Get the hash value from embedded DLL/assembly
string fileHash = BitConverter.ToString(sha1.ComputeHash(ba)).Replace("-", string.Empty);
// Define the temporary storage location of the DLL/assembly
tempFile = Path.GetTempPath() + fileName;
// Determines whether the DLL/assembly is existed or not
if (File.Exists(tempFile))
{
// Get the hash value of the existed file
byte[] bb = File.ReadAllBytes(tempFile);
string fileHash2 = BitConverter.ToString(sha1.ComputeHash(bb)).Replace("-", string.Empty);
// Compare the existed DLL/assembly with the Embedded DLL/assembly
if (fileHash == fileHash2)
{
// Same file
fileOk = true;
}
else
{
// Not same
fileOk = false;
}
}
else
{
// The DLL/assembly is not existed yet
fileOk = false;
}
}
// Create the file on disk
if (!fileOk)
{
File.WriteAllBytes(tempFile, ba);
}
// Load it into memory
asm = Assembly.LoadFile(tempFile);
// Add the loaded DLL/assembly into dictionary
dic.Add(asm.FullName, asm);
}
/// <summary>
/// Retrieve specific loaded DLL/assembly from memory
/// </summary>
/// <param name="assemblyFullName"></param>
/// <returns></returns>
public static Assembly Get(string assemblyFullName)
{
if (dic == null || dic.Count == 0)
return null;
if (dic.ContainsKey(assemblyFullName))
return dic[assemblyFullName];
return null;
// Don't throw Exception if the dictionary does not contain the requested assembly.
// This is because the event of AssemblyResolve will be raised for every
// Embedded Resources (such as pictures) of the projects.
// Those resources wil not be loaded by this class and will not exist in dictionary.
}
internal static void Copy(string embeddedResource, string fileName)
{
byte[] ba = null;
Assembly curAsm = Assembly.GetExecutingAssembly();
using (Stream stm = curAsm.GetManifestResourceStream(embeddedResource))
{
// Either the file is not existed or it is not mark as embedded resource
if (stm == null)
throw new Exception(embeddedResource + " is not found in Embedded Resources.");
// Get byte[] from the file from embedded resource
ba = new byte[(int)stm.Length];
stm.Read(ba, 0, (int)stm.Length);
}
bool fileOk = false;
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
// Get the hash value from embedded DLL/assembly
string fileHash = BitConverter.ToString(sha1.ComputeHash(ba)).Replace("-", string.Empty);
// Determines whether the DLL/assembly is existed or not
if (File.Exists(fileName))
{
// Get the hash value of the existed file
byte[] bb = File.ReadAllBytes(fileName);
string fileHash2 = BitConverter.ToString(sha1.ComputeHash(bb)).Replace("-", string.Empty);
// Compare the existed DLL/assembly with the Embedded DLL/assembly
if (fileHash == fileHash2)
{
// Same file
fileOk = true;
}
else
{
// Not same
fileOk = false;
}
}
else
{
// The DLL/assembly is not existed yet
fileOk = false;
}
}
// Create the file on disk
if (!fileOk)
{
try
{
File.WriteAllBytes(fileName, ba);
}
catch (Exception ex)
{
Utils.Instance.DebugWriteLine(ex.ToString());
}
}
}
}
}

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SmartAquaViewer.Classes;
namespace SmartAquaViewer.INI
{
class INIManager
{
private readonly string strINIPath;
[DllImport("kernel32", CharSet = CharSet.Ansi)]
private static extern long WritePrivateProfileString(String section, String key, String val, String filePath);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
private static extern int GetPrivateProfileString(String section, String key, String def, StringBuilder retVal, int size, String filePath);
public INIManager(String INIPath)
{
strINIPath = INIPath;
if (!ExistINI())
{
CreateIni();
}
else
{
CheckAndInsertIni();
}
}
public void CreateIni()
{
WriteValue("CONFIG", Constants.Config.TITLE, "SmartAquaViwer");
WriteValue("CONFIG", Constants.Config.DATA_FILE_PATH, Constants.Directories.DATA_FOLDER);
}
public bool ExistINI()
{
return File.Exists(strINIPath);
}
public void CheckAndInsertIni()
{
CheckAndInsert("CONFIG", Constants.Config.TITLE, "SmartAquaViwer");
CheckAndInsert("CONFIG", Constants.Config.DATA_FILE_PATH, Constants.Directories.DATA_FOLDER);
}
public void CheckAndInsert(String strSection, String strKey, String strValue)
{
string key = ReadValue(strSection, strKey);
if (key == null || key.Trim() == "")
{
WriteValue(strSection, strKey, strValue);
}
}
public void WriteValue(String strSection, String strKey, String strValue)
{
WritePrivateProfileString(strSection, strKey, strValue, strINIPath);
}
public void DeleteSection(String strSection)
{
WritePrivateProfileString(strSection, null, null, strINIPath);
}
public string ReadValue(String strSection, String Key)
{
return ReadValue(strSection, Key, "");
}
public string ReadValue(String strSection, String Key, String def)
{
var strValue = new StringBuilder(255);
int i = GetPrivateProfileString(strSection, Key, def, strValue, 255, strINIPath);
return strValue.ToString();
}
}
}

@ -8,6 +8,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using SmartAquaViewer.Classes;
using SmartAquaViewer.DataAnalysis; using SmartAquaViewer.DataAnalysis;
using SmartAquaViewer.Model; using SmartAquaViewer.Model;
@ -22,9 +23,21 @@ namespace SmartAquaViewer
{ {
InitializeComponent(); InitializeComponent();
Loaded += MainWindow_Loaded;
StateChanged += MainWindow_StateChanged; StateChanged += MainWindow_StateChanged;
} }
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
ConfigData.Instance.LoadConfig();
CreateDirectories();
}
private void CreateDirectories()
{
Utils.Instance.CreateDirectory(Constants.Directories.DATA_FOLDER);
}
private void WindowNormal_Click(object sender, RoutedEventArgs e) private void WindowNormal_Click(object sender, RoutedEventArgs e)
{ {
WindowState = WindowState.Normal; WindowState = WindowState.Normal;

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartAquaViewer.Classes;
namespace SmartAquaViewer.Model
{
public class ConfigData
{
public static ConfigData Instance { get; } = new ConfigData();
public string Title { get; set; }
public string DataFilePath { get; set; }
public ConfigData()
{
}
public void LoadConfig()
{
Title = Utils.Instance.GetTitle();
DataFilePath = Utils.Instance.GetDataFilePath();
}
}
}

@ -17,11 +17,13 @@ namespace SmartAquaViewer.Model
public ObservableCollection<WaterQualityVO> WaterQualityList { get; set; } public ObservableCollection<WaterQualityVO> WaterQualityList { get; set; }
public ReadOnlyObservableCollection<WaterQualityVO> WaterQualityView { get; } public ReadOnlyObservableCollection<WaterQualityVO> WaterQualityView { get; }
public ObservableCollection<CCTVInfo> CctvInfoList { get; set; }
private Datas() private Datas()
{ {
WaterQualityList = new ObservableCollection<WaterQualityVO>(); WaterQualityList = new ObservableCollection<WaterQualityVO>();
WaterQualityView = new ReadOnlyObservableCollection<WaterQualityVO>(WaterQualityList); WaterQualityView = new ReadOnlyObservableCollection<WaterQualityVO>(WaterQualityList);
CctvInfoList = new ObservableCollection<CCTVInfo>();
} }
public ObservableCollection<WaterQualityVO> GetWaterQualityVO() public ObservableCollection<WaterQualityVO> GetWaterQualityVO()
@ -39,6 +41,11 @@ namespace SmartAquaViewer.Model
OnPropertyChanged(nameof(WaterQualityList)); OnPropertyChanged(nameof(WaterQualityList));
} }
public void SetCCTVInfoList()
{
}
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string name) => private void OnPropertyChanged(string name) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

@ -149,8 +149,11 @@
<Style x:Key="DataGridStyle" TargetType="DataGrid"> <Style x:Key="DataGridStyle" TargetType="DataGrid">
<Setter Property="EnableRowVirtualization" Value="True"/> <Setter Property="EnableRowVirtualization" Value="True"/>
<Setter Property="EnableColumnVirtualization" Value="True"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/> <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/> <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="HeadersVisibility" Value="Column"/> <Setter Property="HeadersVisibility" Value="Column"/>
<Setter Property="AutoGenerateColumns" Value="False"/> <Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="IsReadOnly" Value="True"/> <Setter Property="IsReadOnly" Value="True"/>

@ -41,6 +41,8 @@
ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle}" ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
helper:DataGridAutoPageSizeBehavior.Enable="True" helper:DataGridAutoPageSizeBehavior.Enable="True"
helper:DataGridAutoPageSizeBehavior.Pager="{Binding TanksPager}" helper:DataGridAutoPageSizeBehavior.Pager="{Binding TanksPager}"
helper:DataGridAutoPageSizeBehavior.Suspend="{Binding IsOpenMode}"
helper:DataGridAutoPageSizeBehavior.ThrottleMs="120"
Grid.Row="1" Margin="15 0" Grid.Row="1" Margin="15 0"
ColumnWidth="*" RowHeight="30" ColumnWidth="*" RowHeight="30"
Background="Transparent" Background="Transparent"
@ -185,6 +187,8 @@
Style="{StaticResource DataGridStyle}" Style="{StaticResource DataGridStyle}"
ColumnWidth="*" RowHeight="30" ColumnWidth="*" RowHeight="30"
helper:DataGridAutoPageSizeBehavior.Enable="True" helper:DataGridAutoPageSizeBehavior.Enable="True"
helper:DataGridAutoPageSizeBehavior.Suspend="{Binding IsOpenMode}"
helper:DataGridAutoPageSizeBehavior.ThrottleMs="120"
Grid.Row="1" Margin="15 0 15 0" Grid.Row="1" Margin="15 0 15 0"
Background="Transparent" Background="Transparent"
RowStyle="{StaticResource DataGridRowStyle}" RowStyle="{StaticResource DataGridRowStyle}"
@ -310,6 +314,8 @@
Style="{StaticResource DataGridStyle}" Style="{StaticResource DataGridStyle}"
ColumnWidth="*" RowHeight="30" ColumnWidth="*" RowHeight="30"
helper:DataGridAutoPageSizeBehavior.Enable="True" helper:DataGridAutoPageSizeBehavior.Enable="True"
helper:DataGridAutoPageSizeBehavior.Pager="{Binding TanksPager}"
helper:DataGridAutoPageSizeBehavior.Suspend="{Binding IsOpenMode}"
Grid.Row="1" Margin="15 0 15 0" Grid.Row="1" Margin="15 0 15 0"
Background="Transparent" Background="Transparent"
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
@ -431,7 +437,8 @@
</Grid> </Grid>
</Grid> </Grid>
<md:DrawerHost.BottomDrawerContent> <md:DrawerHost.BottomDrawerContent>
<Border Height="450" BorderThickness="0 3 0 0" BorderBrush="#455569"> <Border x:Name="BottomDrawerRoot" Height="450"
BorderThickness="0 3 0 0" BorderBrush="#455569">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="550"/> <ColumnDefinition Width="550"/>

@ -144,14 +144,14 @@ namespace SmartAquaViewer.ViewModel
{ {
DeviceId = "000001", DeviceId = "000001",
DeviceName = "CCTV 1", DeviceName = "CCTV 1",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-211", RtspUrl = "rtsp://210.217.121.58:8554/CAM-07",
Status = CCTVStatus.Disconnected Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000002", DeviceId = "000002",
DeviceName = "CCTV 2", DeviceName = "CCTV 2",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-212", RtspUrl = "rtsp://210.217.121.58:8554/CAM-08",
Status = CCTVStatus.Disconnected Status = CCTVStatus.Disconnected
}, },
new() new()

Loading…
Cancel
Save