feat: CCTV 목록 출력 및 시작/중지 기능 추가

prototype
HyungJune Kim 10 months ago
parent a47bf94ee7
commit 356f3b9c03

@ -6,13 +6,13 @@
xmlns:local="clr-namespace:SmartAquaViewer.Controls" xmlns:local="clr-namespace:SmartAquaViewer.Controls"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Border> <Border BorderThickness="1" BorderBrush="#243851">
<Grid Background="Transparent"> <Grid Background="Transparent">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="24"></RowDefinition> <RowDefinition Height="24"></RowDefinition>
<RowDefinition Height="*"></RowDefinition> <RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Border Grid.RowSpan="2" x:Name="bdrNoSignalContainer" Visibility="Collapsed"> <Border Grid.RowSpan="2" x:Name="bdrNoSignalContainer" Visibility="{Binding IsPlayingVIsibility}">
<Border.BorderBrush> <Border.BorderBrush>
<SolidColorBrush Color="#394861" Opacity="0.4"></SolidColorBrush> <SolidColorBrush Color="#394861" Opacity="0.4"></SolidColorBrush>
</Border.BorderBrush> </Border.BorderBrush>

@ -93,9 +93,8 @@
CommandParameter="{Binding Tag, RelativeSource={RelativeSource Self}}"/> CommandParameter="{Binding Tag, RelativeSource={RelativeSource Self}}"/>
</UniformGrid> </UniformGrid>
</Border> </Border>
<Border Grid.Row="2" Grid.Column="1" Margin="0 10 10 10"
BorderBrush="#2d374c" BorderThickness="2"> <!--기능 화면--> <ContentControl x:Name="contentControl" Content="{Binding SelectedViewModel}"
<ContentControl x:Name="contentControl" Content="{Binding SelectedViewModel}"/> Grid.Row="2" Grid.Column="1" Margin="0 10 10 10"/>
</Border>
</Grid> </Grid>
</Window> </Window>

@ -1,16 +1,35 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace SmartAquaViewer.Model namespace SmartAquaViewer.Model
{ {
public class CCTVInfo public class CCTVInfo : INotifyPropertyChanged
{ {
public string? DeviceId { get; set; } public string? DeviceId { get; set; }
public string? DeviceName { get; set; } public string? DeviceName { get; set; }
public string? RtspUrl { get; set; } public string? RtspUrl { get; set; }
public string? Status { get; set; }
private CCTVStatus? _status;
public CCTVStatus? Status
{
get => _status;
set
{
if (_status != value)
{
_status = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
} }
} }

@ -25,6 +25,7 @@ namespace SmartAquaViewer.Model
public enum StepFieldKind public enum StepFieldKind
{ {
Time,
Status, // 전원/상태 Status, // 전원/상태
Sensor, // 센서 값 Sensor, // 센서 값
Energy, // 에너지 소비량 Energy, // 에너지 소비량
@ -42,4 +43,10 @@ namespace SmartAquaViewer.Model
Energy, Energy,
GreenhouseGas GreenhouseGas
} }
public enum CCTVStatus
{
Disconnected,
Connected
}
} }

@ -177,4 +177,30 @@
<Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/>
</Style> </Style>
<Style x:Key="GridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<Border BorderThickness="0,0,0,1" BorderBrush="Black" Background="#2d374f">
<TextBlock Text="{TemplateBinding Content}"
Foreground="White"
Padding="5,5,5,0"
Width="{TemplateBinding Width}"
TextAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
</Style>
<Style x:Key="GridViewTextBlockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontFamily" Value="{StaticResource SCDream3}"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</ResourceDictionary> </ResourceDictionary>

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

@ -21,6 +21,8 @@
<None Remove="Fonts\SCDream8.otf" /> <None Remove="Fonts\SCDream8.otf" />
<None Remove="Fonts\SCDream9.otf" /> <None Remove="Fonts\SCDream9.otf" />
<None Remove="Resources\Images\arrow_down.png" /> <None Remove="Resources\Images\arrow_down.png" />
<None Remove="Resources\Images\arrow_left.png" />
<None Remove="Resources\Images\arrow_right.png" />
<None Remove="Resources\Images\arrow_up.png" /> <None Remove="Resources\Images\arrow_up.png" />
<None Remove="Resources\Images\background.png" /> <None Remove="Resources\Images\background.png" />
<None Remove="Resources\Images\ListImage.png" /> <None Remove="Resources\Images\ListImage.png" />
@ -70,6 +72,12 @@
<Resource Include="Fonts\SCDream8.otf" /> <Resource Include="Fonts\SCDream8.otf" />
<Resource Include="Fonts\SCDream9.otf" /> <Resource Include="Fonts\SCDream9.otf" />
<Resource Include="Resources\Images\arrow_down.png" /> <Resource Include="Resources\Images\arrow_down.png" />
<Resource Include="Resources\Images\arrow_left.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Images\arrow_right.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Images\arrow_up.png" /> <Resource Include="Resources\Images\arrow_up.png" />
<Resource Include="Resources\Images\background.png" /> <Resource Include="Resources\Images\background.png" />
<Resource Include="Resources\Images\ListImage.png" /> <Resource Include="Resources\Images\ListImage.png" />

@ -6,10 +6,15 @@
xmlns:local="clr-namespace:SmartAquaViewer.View" xmlns:local="clr-namespace:SmartAquaViewer.View"
xmlns:classes="clr-namespace:SmartAquaViewer.Classes" xmlns:classes="clr-namespace:SmartAquaViewer.Classes"
xmlns:controls="clr-namespace:SmartAquaViewer.Controls" xmlns:controls="clr-namespace:SmartAquaViewer.Controls"
xmlns:helper="clr-namespace:SmartAquaViewer.Helper"
xmlns:model="clr-namespace:SmartAquaViewer.Model"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Border >
<md:DrawerHost RightDrawerBackground="Transparent" IsRightDrawerOpen="{Binding IsOpenMode}" OpenMode="Standard">
<Grid Background="Transparent"> <Grid Background="Transparent">
<ItemsControl ItemsSource="{Binding PlayerVMs}"> <ItemsControl ItemsSource="{Binding PlayerVMs}" Margin="0 0 30 0">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<UniformGrid x:Name="ugrdFFPlayer" Rows="{Binding RowCount}" Columns="{Binding ColumnCount}" /> <UniformGrid x:Name="ugrdFFPlayer" Rows="{Binding RowCount}" Columns="{Binding ColumnCount}" />
@ -21,5 +26,109 @@
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
<Grid HorizontalAlignment="Right">
<Button Tag="left" Margin="0"
Style="{StaticResource ImageButtonStyle}" Width="25" Command="{Binding ChangeDrawerStatusCommand}"
VerticalAlignment="Center" HorizontalAlignment="Right" Visibility="{Binding BtnVisibilityLeft}"
helper:ImageButtonHelper.ImageSource="/Resources/Images/arrow_left.png"/>
<Button Tag="right" Margin="0"
Style="{StaticResource ImageButtonStyle}" Width="25" Command="{Binding ChangeDrawerStatusCommand}"
VerticalAlignment="Center" HorizontalAlignment="Right" Visibility="{Binding BtnVisibilityRight}"
helper:ImageButtonHelper.ImageSource="/Resources/Images/arrow_right.png"/>
</Grid> </Grid>
</Grid>
<md:DrawerHost.RightDrawerContent>
<Border Width="300"
BorderBrush="#2d374c" BorderThickness="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid>
<Border VerticalAlignment="Center" Margin="40 0">
<md:PackIcon Kind="Cctv" Foreground="#ffd663" Width="30" Height="30"/>
</Border>
<TextBlock Text="CCTV 목록" FontFamily="{StaticResource SCDream5}"
FontSize="20" FontWeight="Bold" Foreground="White"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<ListView Grid.Row="1" Margin="10 0"
ItemsSource="{Binding CCTVInfoList}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
BorderThickness="0" Background="Transparent">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridViewColumnHeaderStyle}">
<GridViewColumn Header="상태" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Ellipse Width="15" Height="15" VerticalAlignment="Center" HorizontalAlignment="Center">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="{x:Static model:CCTVStatus.Connected}">
<Setter Property="Fill" Value="LimeGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="ID" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding DeviceId}" Style="{StaticResource GridViewTextBlockStyle}"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="CCTV" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock
Text="{Binding DeviceName}"
Style="{StaticResource GridViewTextBlockStyle}"/>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<!--하단 버튼-->
<Grid Grid.Row="2">
<Button Padding="0" Margin="5" Content="재생" Visibility="{Binding BtnVisibilityPlay}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Style="{StaticResource MaterialDesignFlatMidBgButton}"
Command="{Binding PlayAllCCTVCommand}">
<Button.ToolTip>
<ToolTip Content="CCTV 재생"/>
</Button.ToolTip>
</Button>
<Button Padding="0" Margin="5" Content="중지" Visibility="{Binding BtnVisibilityStop}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Style="{StaticResource MaterialDesignFlatMidBgButton}"
Command="{Binding StopAllCCTVCommand}">
<Button.ToolTip>
<ToolTip Content="CCTV 재생"/>
</Button.ToolTip>
</Button>
</Grid>
</Grid>
</Border>
</md:DrawerHost.RightDrawerContent>
</md:DrawerHost>
</Border>
</UserControl> </UserControl>

@ -14,6 +14,7 @@
<classes:InverseBoolConverter x:Key="InverseBoolConverter"/> <classes:InverseBoolConverter x:Key="InverseBoolConverter"/>
</UserControl.Resources> </UserControl.Resources>
<Border BorderBrush="#2d374c" BorderThickness="2">
<Grid Background="Transparent"> <Grid Background="Transparent">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="160"/> <RowDefinition Height="160"/>
@ -365,4 +366,5 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/> HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Border> </Border>
</Grid> </Grid>
</Border>
</UserControl> </UserControl>

@ -24,7 +24,7 @@
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Image Source="/Resources/Images/ListImage.png" <Image Source="/Resources/Images/ListImage.png"
Width="35" Margin="20 0"/> Width="35" Margin="20 0"/>
<TextBlock Text="파일 목록" <TextBlock Text="파일 목록" FontFamily="{StaticResource SCDream5}"
FontSize="20" FontWeight="Bold" Foreground="White" FontSize="20" FontWeight="Bold" Foreground="White"
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
<Button Width="40" Height="40" <Button Width="40" Height="40"

@ -14,6 +14,7 @@
<classes:InverseBoolConverter x:Key="InverseBoolConverter"/> <classes:InverseBoolConverter x:Key="InverseBoolConverter"/>
</UserControl.Resources> </UserControl.Resources>
<Border BorderBrush="#2d374c" BorderThickness="2">
<Grid Background="Transparent"> <Grid Background="Transparent">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="160"/> <RowDefinition Height="160"/>
@ -362,4 +363,5 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/> HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Border> </Border>
</Grid> </Grid>
</Border>
</UserControl> </UserControl>

@ -17,7 +17,7 @@
<classes:BoolToPowerConverter x:Key="BoolToPowerConverter"/> <classes:BoolToPowerConverter x:Key="BoolToPowerConverter"/>
</UserControl.Resources> </UserControl.Resources>
<Border> <Border BorderBrush="#2d374c" BorderThickness="2">
<md:DrawerHost BottomDrawerBackground="Transparent" IsBottomDrawerOpen="{Binding IsOpenMode}" OpenMode="Standard"> <md:DrawerHost BottomDrawerBackground="Transparent" IsBottomDrawerOpen="{Binding IsOpenMode}" OpenMode="Standard">
<Grid Background="Transparent"> <Grid Background="Transparent">
<Grid.RowDefinitions> <Grid.RowDefinitions>

@ -6,6 +6,9 @@ using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using SmartAquaViewer.Controls;
using SmartAquaViewer.DataAnalysis; using SmartAquaViewer.DataAnalysis;
using SmartAquaViewer.Model; using SmartAquaViewer.Model;
@ -13,7 +16,7 @@ namespace SmartAquaViewer.ViewModel
{ {
public class CCTVViewModel : INotifyPropertyChanged public class CCTVViewModel : INotifyPropertyChanged
{ {
public List<CCTVInfo> CCTVInfoList { get; } = new List<CCTVInfo>(); public ObservableCollection<CCTVInfo> CCTVInfoList { get; } = new ObservableCollection<CCTVInfo>();
public ObservableCollection<FFPlayerViewModel> PlayerVMs { get; } = new(); public ObservableCollection<FFPlayerViewModel> PlayerVMs { get; } = new();
@ -45,72 +48,179 @@ namespace SmartAquaViewer.ViewModel
} }
} }
private bool _isOpenMode;
public bool IsOpenMode
{
get => _isOpenMode;
set
{
if (_isOpenMode != value)
{
_isOpenMode = value;
OnPropertyChanged();
BtnVisibilityLeft = _isOpenMode ? Visibility.Collapsed : Visibility.Visible;
BtnVisibilityRight = _isOpenMode ? Visibility.Visible : Visibility.Collapsed;
}
}
}
private Visibility _btnVisibilityLeft;
public Visibility BtnVisibilityLeft
{
get => _btnVisibilityLeft;
set
{
if (_btnVisibilityLeft != value)
{
_btnVisibilityLeft = value;
OnPropertyChanged();
}
}
}
private Visibility _btnVisibilityRight;
public Visibility BtnVisibilityRight
{
get => _btnVisibilityRight;
set
{
if (_btnVisibilityRight != value)
{
_btnVisibilityRight = value;
OnPropertyChanged();
}
}
}
private Visibility _btnVisibilityPlay;
public Visibility BtnVisibilityPlay
{
get => _btnVisibilityPlay;
set
{
if (_btnVisibilityPlay != value)
{
_btnVisibilityPlay = value;
OnPropertyChanged();
}
}
}
private Visibility _btnVisibilityStop;
public Visibility BtnVisibilityStop
{
get => _btnVisibilityStop;
set
{
if (_btnVisibilityStop != value)
{
_btnVisibilityStop = value;
OnPropertyChanged();
}
}
}
public ICommand ChangeDrawerStatusCommand { get; }
public ICommand PlayAllCCTVCommand { get; }
public ICommand StopAllCCTVCommand { get; }
public CCTVViewModel() public CCTVViewModel()
{ {
ColumnCount = 4; // Default value ColumnCount = 4; // Default value
RowCount = 2; // Default value RowCount = 2; // Default value
CCTVInfoList = new List<CCTVInfo>() IsOpenMode = false;
BtnVisibilityRight = Visibility.Collapsed;
BtnVisibilityStop = Visibility.Collapsed;
CCTVInfoList = new ObservableCollection<CCTVInfo>()
{ {
new() new()
{ {
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-211",
Status = "Active" 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-212",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000003", DeviceId = "000003",
DeviceName = "CCTV 3", DeviceName = "CCTV 3",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-01", RtspUrl = "rtsp://210.217.121.58:8554/CAM-01",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000004", DeviceId = "000004",
DeviceName = "CCTV 4", DeviceName = "CCTV 4",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-02", RtspUrl = "rtsp://210.217.121.58:8554/CAM-02",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000005", DeviceId = "000005",
DeviceName = "CCTV 5", DeviceName = "CCTV 5",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-03", RtspUrl = "rtsp://210.217.121.58:8554/CAM-03",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000006", DeviceId = "000006",
DeviceName = "CCTV 6", DeviceName = "CCTV 6",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-04", RtspUrl = "rtsp://210.217.121.58:8554/CAM-04",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000007", DeviceId = "000007",
DeviceName = "CCTV 7", DeviceName = "CCTV 7",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-05", RtspUrl = "rtsp://210.217.121.58:8554/CAM-05",
Status = "Active" Status = CCTVStatus.Disconnected
}, },
new() new()
{ {
DeviceId = "000008", DeviceId = "000008",
DeviceName = "CCTV 8", DeviceName = "CCTV 8",
RtspUrl = "rtsp://210.217.121.58:8554/CAM-06", RtspUrl = "rtsp://210.217.121.58:8554/CAM-06",
Status = "Active" Status = CCTVStatus.Disconnected
} }
}; };
BuildPlayers(CCTVInfoList); BuildPlayers(CCTVInfoList);
ChangeDrawerStatusCommand = new RelayCommand(_ => IsOpenMode = !IsOpenMode);
PlayAllCCTVCommand = new RelayCommand(PlayAllCCTV);
StopAllCCTVCommand = new RelayCommand(StopAllCCTV);
}
private void PlayAllCCTV(object obj)
{
foreach (var ff in PlayerVMs)
ff.StartMedia(ff.CCTVInfo.RtspUrl!);
BtnVisibilityPlay = Visibility.Collapsed;
BtnVisibilityStop = Visibility.Visible;
}
private void StopAllCCTV(object obj)
{
foreach (var ff in PlayerVMs)
ff.ClosePlayer();
BtnVisibilityPlay = Visibility.Visible;
BtnVisibilityStop = Visibility.Collapsed;
} }
public void BuildPlayers(IEnumerable<CCTVInfo> infos) public void BuildPlayers(IEnumerable<CCTVInfo> infos)

@ -1,14 +1,7 @@
using System; using System.ComponentModel;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
@ -30,14 +23,21 @@ namespace SmartAquaViewer.ViewModel
set { _currentFrame = value; OnPropertyChanged(); } set { _currentFrame = value; OnPropertyChanged(); }
} }
private Visibility _isPlayingVIsibility;
public Visibility IsPlayingVIsibility
{
get => _isPlayingVIsibility;
set { _isPlayingVIsibility = value; OnPropertyChanged(); }
}
//private readonly System.Windows.Controls.Image _img; //private readonly System.Windows.Controls.Image _img;
private readonly object _lockObject = new object();
private Thread _videoThread; private Thread _videoThread;
private Thread _renderingThread; private Thread _renderingThread;
private CancellationTokenSource _videoCts; private CancellationTokenSource _videoCts;
private CancellationTokenSource _renderCts; private CancellationTokenSource _renderCts;
private readonly object _lockObject = new object();
private readonly Queue<AVFrame> _frameQueue = new(); // lock 불필요 private readonly Queue<AVFrame> _frameQueue = new(); // lock 불필요
private volatile bool _disposed; private volatile bool _disposed;
@ -48,11 +48,14 @@ namespace SmartAquaViewer.ViewModel
CCTVInfo = cctvInfo; CCTVInfo = cctvInfo;
_ui = Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher; // UI 디스패처 보관 _ui = Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher; // UI 디스패처 보관
StartMedia(CCTVInfo.RtspUrl!); IsPlayingVIsibility = Visibility.Visible;
} }
public void StartMedia(string rtspURL) public void StartMedia(string rtspURL)
{ {
IsPlayingVIsibility = Visibility.Collapsed;
CCTVInfo.Status = CCTVStatus.Connected;
_videoCts = new CancellationTokenSource(); _videoCts = new CancellationTokenSource();
_renderCts = new CancellationTokenSource(); _renderCts = new CancellationTokenSource();
@ -178,6 +181,11 @@ namespace SmartAquaViewer.ViewModel
_videoCts?.Dispose(); _videoCts?.Dispose();
_renderCts?.Dispose(); _renderCts?.Dispose();
CurrentFrame = null;
IsPlayingVIsibility = Visibility.Visible;
CCTVInfo.Status = CCTVStatus.Disconnected;
} }
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;

@ -326,7 +326,7 @@ namespace SmartAquaViewer.ViewModel
.ToList(); .ToList();
// X축 라벨 // X축 라벨
xAxis.Labels.AddRange(timeBuckets.Select(t => t.ToString("MM-dd HH:mm"))); xAxis.Labels.AddRange(timeBuckets.Select(t => t.ToString("HH:mm:ss")));
var allTankIds = collection.SelectMany(w => w.Tanks).Select(t => t.Number).Distinct().OrderBy(id => id).ToList(); var allTankIds = collection.SelectMany(w => w.Tanks).Select(t => t.Number).Distinct().OrderBy(id => id).ToList();
var tankIds = (selectedTankNums == null || !selectedTankNums.Any()) var tankIds = (selectedTankNums == null || !selectedTankNums.Any())

@ -17,19 +17,7 @@ namespace SmartAquaViewer.ViewModel
{ {
public class MainViewModel : INotifyPropertyChanged public class MainViewModel : INotifyPropertyChanged
{ {
private string _appTitle; public string AppTitle { get; set; } = string.Empty;
public string AppTitle
{
get => _appTitle;
set
{
if (_appTitle != value)
{
_appTitle = value;
OnPropertyChanged(nameof(AppTitle));
}
}
}
private object? _selectedViewModel; private object? _selectedViewModel;
public object? SelectedViewModel public object? SelectedViewModel

@ -1,18 +1,11 @@
using System; using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
using SmartAquaViewer.Controls; using SmartAquaViewer.Controls;
using SmartAquaViewer.DataAnalisys;
using SmartAquaViewer.DataAnalysis; using SmartAquaViewer.DataAnalysis;
using SmartAquaViewer.Model; using SmartAquaViewer.Model;
@ -52,8 +45,6 @@ namespace SmartAquaViewer.ViewModel
public ObservableCollection<TanksByTime> TanksByTimes { get; } = new(); public ObservableCollection<TanksByTime> TanksByTimes { get; } = new();
private ObservableCollection<int> SelectedTankNumbers { get; } = new();
private MonitorTab _selectedTab; private MonitorTab _selectedTab;
public MonitorTab SelectedTab public MonitorTab SelectedTab
{ {
@ -355,16 +346,6 @@ namespace SmartAquaViewer.ViewModel
var keys = SelectedWaterTanks.Keys.ToList(); var keys = SelectedWaterTanks.Keys.ToList();
var selectedTanks = WaterQualityList
.SelectMany(wq => wq.Tanks.Select(tank => new { Tank = tank, VO = wq }))
.Where(x => keys.Contains(x.Tank.Number))
.GroupBy(x => x.Tank.Number)
.ToDictionary(
g => g.Key,
g => new ObservableCollection<WaterQualityVO>(
g.Select(x => x.VO).OrderBy(vo => vo.RecordedTime))
);
GraphControlVM.SetTankLineGraph(WaterQualityList, keys, SelectedXField, SelectedYField, ShowMarkers, ShowLegends); GraphControlVM.SetTankLineGraph(WaterQualityList, keys, SelectedXField, SelectedYField, ShowMarkers, ShowLegends);
} }
@ -377,7 +358,7 @@ namespace SmartAquaViewer.ViewModel
var keys = SelectedWaterTanks.Keys.ToList(); var keys = SelectedWaterTanks.Keys.ToList();
GraphControlVM.SetBoxPlot(WaterQualityList, keys, SelectedXField, SelectedYField, BoxWidth, boxTimeSpan); GraphControlVM.SetBoxPlot(WaterQualityList, keys, SelectedXField!, SelectedYField, BoxWidth, boxTimeSpan);
} }
private void SetGraphData_Scatter_Tank() private void SetGraphData_Scatter_Tank()
@ -387,7 +368,7 @@ namespace SmartAquaViewer.ViewModel
var keys = SelectedWaterTanks.Keys.ToList(); var keys = SelectedWaterTanks.Keys.ToList();
GraphControlVM.SetScatterPlot(WaterQualityList, SelectedXField, SelectedYField, keys, ScatterMarkerSize, ShowRegression, ShowLegends); GraphControlVM.SetScatterPlot(WaterQualityList, SelectedXField!, SelectedYField, keys, ScatterMarkerSize, ShowRegression, ShowLegends);
} }
private void SetGraphType() private void SetGraphType()
@ -414,7 +395,7 @@ namespace SmartAquaViewer.ViewModel
{ {
SelectedGraphIndex = -1; SelectedGraphIndex = -1;
SelectedGraphIndex = GraphTypes.Count > 0 ? 0 : -1; SelectedGraphIndex = GraphTypes.Count > 0 ? 0 : -1;
}), System.Windows.Threading.DispatcherPriority.Background); }), DispatcherPriority.Background);
} }
private void RebuildAvailableFields() private void RebuildAvailableFields()
@ -422,7 +403,7 @@ namespace SmartAquaViewer.ViewModel
AvailableFields.Clear(); AvailableFields.Clear();
// 공통 시간 // 공통 시간
AvailableFields.Add(new FieldItem { Name = "RecordedTime", Display = "시간", DataType = typeof(DateTime) }); AvailableFields.Add(new FieldItem { Name = "RecordedTime", Display = "시간", DataType = typeof(DateTime), Kind = StepFieldKind.Time });
if (SelectedTab == MonitorTab.Tank) if (SelectedTab == MonitorTab.Tank)
{ {
@ -496,7 +477,10 @@ namespace SmartAquaViewer.ViewModel
if ((SelectedGraphType == GraphType.LINE if ((SelectedGraphType == GraphType.LINE
|| SelectedGraphType == GraphType.STEP || SelectedGraphType == GraphType.STEP
|| SelectedGraphType == GraphType.SCATTER) || SelectedGraphType == GraphType.SCATTER)
&& f.Name.Equals("Number")) continue; && f.Name!.Equals("Number")) continue;
if (SelectedGraphType == GraphType.LINE
&& (f.Kind.Equals(StepFieldKind.Status)
|| f.Name!.Equals("Filtering.InverterControllerStatus"))) continue;
XFieldCandidates.Add(f); XFieldCandidates.Add(f);
if (SelectedGraphType == GraphType.STEP || SelectedGraphType == GraphType.BOX) break; if (SelectedGraphType == GraphType.STEP || SelectedGraphType == GraphType.BOX) break;
} }

Loading…
Cancel
Save