为三亚做准备:
导入起飞位置 导入C4D关键帧 碰撞检测不暂停任务 起飞摆放高度 添加分组设置 灯光设置优化 当前检测碰撞为1.8米
This commit is contained in:
parent
9c70ad73ea
commit
cce5722a52
@ -33,7 +33,6 @@ namespace Plane.FormationCreator
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
|
||||
|
||||
ServiceLocatorConfigurer.Instance.Configure();
|
||||
|
||||
_logger = ServiceLocator.Current.GetInstance<ILogger>();
|
||||
_copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
|
||||
_formationController = ServiceLocator.Current.GetInstance<FormationController>();
|
||||
|
@ -145,6 +145,7 @@ namespace Plane.FormationCreator.Formation
|
||||
{
|
||||
_selectCopterAction(copter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SelectedCoptersChangedEventArgs : EventArgs
|
||||
|
@ -14,7 +14,7 @@ namespace Plane.FormationCreator.Formation
|
||||
{
|
||||
public const float GpsArrivedDis = 2.0f; //GPS模式下航点到达精度
|
||||
public const float RTKArrivedDis = 1.5f; //RTK模式航点达到精度
|
||||
public const float GpsCloseDis = 1.5f; //GPS模式下碰撞检测最近距离
|
||||
public const float GpsCloseDis = 1.8f; //GPS模式下碰撞检测最近距离
|
||||
public const float RTKClosedDis = 0.5f; //RTK模式下碰撞检测最近距离
|
||||
|
||||
|
||||
@ -81,14 +81,14 @@ namespace Plane.FormationCreator.Formation
|
||||
|
||||
public static bool IsTooCloseTo(this ICopter copter, ICopter copter2)
|
||||
{
|
||||
if ((copter.GpsFixType == GpsFixType.RTKFIXED)&& (copter2.GpsFixType == GpsFixType.RTKFIXED))
|
||||
//return false; //效果图用 不检测碰撞
|
||||
if (copter.Altitude < 3 || copter2.Altitude < 3)
|
||||
return false;
|
||||
|
||||
if ((copter.GpsFixType == GpsFixType.RTKFIXED) && (copter2.GpsFixType == GpsFixType.RTKFIXED))
|
||||
return copter.DistanceTo(copter2) < RTKClosedDis; //最近距离0.5米
|
||||
else
|
||||
return copter.DistanceTo(copter2) < GpsCloseDis; //最近距离2米
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,6 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
|
||||
private CopterManager _copterManager;
|
||||
|
||||
|
||||
private int _TakeOffNumAttr = 1;
|
||||
public int TakeOffNumAttr
|
||||
@ -417,6 +416,49 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
}
|
||||
|
||||
public void ImportC4DFlytoTask(string txt)
|
||||
{
|
||||
string[] lines = txt.Replace("\r\n", "\n").Split('\n');
|
||||
if (lines.Length != _copterManager.Copters.Count)
|
||||
return;
|
||||
|
||||
|
||||
var lastTask = Tasks.LastOrDefault();
|
||||
var newTask = new FlightTask(FlightTaskType.FlyTo) { StaggerRoutes = true, FlytoTime = 10, LoiterTime = 10 };
|
||||
int i = 0;
|
||||
foreach (string line in lines)
|
||||
{
|
||||
|
||||
string[] parameters = line.Split(' ');
|
||||
string id = parameters[0];
|
||||
string frame = parameters[1];
|
||||
string x = parameters[2]; //左右 经度
|
||||
string y = parameters[3]; //上下 高度
|
||||
string z = parameters[4]; //前后 纬度
|
||||
Tuple<double, double> observationLatLng = null;
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
OriginLat,
|
||||
OriginLng,
|
||||
90,
|
||||
Convert.ToSingle(x) / 100);
|
||||
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
observationLatLng.Item1,
|
||||
observationLatLng.Item2,
|
||||
0,
|
||||
Convert.ToSingle(z) / 100);
|
||||
|
||||
var thisSingleCopterInfo = FlightTaskSingleCopterInfo.CreateForFlyToTask(
|
||||
_copterManager.Copters[Convert.ToInt32(id)], new LatLng(observationLatLng.Item1 - OriginLat, observationLatLng.Item2 - OriginLng),
|
||||
Convert.ToSingle(y)/100, false);
|
||||
newTask.SingleCopterInfos.Add(thisSingleCopterInfo);
|
||||
i++;
|
||||
}
|
||||
Tasks.Add(newTask);
|
||||
TaskAdded?.Invoke(this, new FlightTaskAddedEventArgs { LastTask = lastTask, AddedTask = newTask });
|
||||
|
||||
}
|
||||
|
||||
public void ImportBlenderFlyToTask(string blenderVectors)
|
||||
{
|
||||
string[] lineVectors = blenderVectors.Replace("\r\n","\n").Split('\n');
|
||||
@ -683,7 +725,7 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
|
||||
//导出任务
|
||||
public string ExportTasks()
|
||||
public IEnumerable<object> ExportTasks()
|
||||
{
|
||||
// For reference.
|
||||
//var tasks = new object[]
|
||||
@ -927,14 +969,13 @@ namespace Plane.FormationCreator.Formation
|
||||
throw new NotImplementedException(type + " task export not implemented.");
|
||||
}
|
||||
});
|
||||
return JsonConvert.SerializeObject(tasks);
|
||||
return tasks;
|
||||
}
|
||||
|
||||
|
||||
//导入任务,可设置导入哪些步骤
|
||||
public void ImportTasksindex(string tasksText,int startindex,int endindex)
|
||||
public void ImportTasksindex(dynamic tasks, int startindex,int endindex)
|
||||
{
|
||||
dynamic tasks = JsonConvert.DeserializeObject(tasksText);
|
||||
var copters = _copterManager.Copters;
|
||||
|
||||
if (Tasks.Count == 0)
|
||||
@ -1125,14 +1166,13 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
|
||||
// 导入任务
|
||||
public void ImportTasks(string tasksText)
|
||||
public void ImportTasks(dynamic tasks)
|
||||
{
|
||||
dynamic tasks = JsonConvert.DeserializeObject(tasksText);
|
||||
var copters = _copterManager.Copters;
|
||||
|
||||
if (Tasks.Count == 0)
|
||||
AddTakeOffTask(copters);
|
||||
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
switch ((FlightTaskType)task.type)
|
||||
@ -1170,6 +1210,16 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
}
|
||||
|
||||
private void ImportCoptersLocate(dynamic coptersLocate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void ImportGroupsInfo(dynamic coptersLocate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Select(int taskIndex, ICopter copter)
|
||||
{
|
||||
this.SelectedTaskIndex = taskIndex;
|
||||
@ -1325,6 +1375,7 @@ namespace Plane.FormationCreator.Formation
|
||||
task.Status = FlightTaskStatus.Running;
|
||||
CurrentRunningTask = task;
|
||||
CurrentRunningTaskIndex = i;
|
||||
Message.Show($"任务{i+1}开始执行");
|
||||
await task.RunAsync().ConfigureAwait(false);
|
||||
// 1. 被暂停时,中断 RunAsync。继续运行时将把此时运行了一半的 CurrentRunningTask 重新运行一遍。
|
||||
if (IsPaused == true)
|
||||
@ -1373,10 +1424,10 @@ namespace Plane.FormationCreator.Formation
|
||||
{
|
||||
if (copter != anotherCopter && copter.IsTooCloseTo(anotherCopter))
|
||||
{
|
||||
Pause();
|
||||
//Pause();
|
||||
Message.Show($"{copter.Name} 与 {anotherCopter.Name} 距离过近,已中止任务。");
|
||||
// Alert.Show($"{copter.Name} 与 {anotherCopter.Name} 距离过近,已中止任务。");
|
||||
return;
|
||||
//return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +144,45 @@ namespace Plane.FormationCreator.Formation
|
||||
}
|
||||
|
||||
|
||||
private int _TakeOffMinTime = 0;
|
||||
public int TakeOffMinTime
|
||||
{
|
||||
get { return _TakeOffMinTime; }
|
||||
set { Set(nameof(TakeOffMinTime), ref _TakeOffMinTime, value); }
|
||||
}
|
||||
|
||||
private int _TakeOffMaxTime = 10;
|
||||
public int TakeOffMaxTime
|
||||
{
|
||||
get { return _TakeOffMaxTime; }
|
||||
set { Set(nameof(TakeOffMaxTime), ref _TakeOffMaxTime, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private ICommand _SetRandomOffWaitDelayCommand;
|
||||
public ICommand SetRandomOffWaitDelayCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SetRandomOffWaitDelayCommand ?? (_SetRandomOffWaitDelayCommand = new RelayCommand<double>(async =>
|
||||
{
|
||||
foreach (FlightTaskSingleCopterInfo info in _flightTaskManager.SelectedTask.SingleCopterInfos)
|
||||
{
|
||||
if (_copterManager.AcceptingControlCopters.Contains(info.Copter))
|
||||
{
|
||||
|
||||
Random random = new Random(Guid.NewGuid().GetHashCode());
|
||||
ushort delay = (ushort)random.Next(TakeOffMinTime, TakeOffMaxTime);
|
||||
info.TakeOffWaitTime = delay;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LatLng LatLngOffset
|
||||
{
|
||||
get
|
||||
|
@ -188,15 +188,34 @@ namespace Plane.FormationCreator.Formation
|
||||
await Task.Delay(10).ConfigureAwait(false); //判断是否到达位置10hz
|
||||
|
||||
|
||||
|
||||
|
||||
// if (info.LEDInfos.Count > 0)
|
||||
// {
|
||||
// string LEDRGB = "";
|
||||
// List<LEDInfo> LedControl = info.LEDInfos.OrderBy(i=>i.Delay).ToList();
|
||||
// for (int i = 0; i < LedControl.Count; i++)
|
||||
// {
|
||||
// var led = LedControl[i];
|
||||
// if (ts.TotalMilliseconds >= led.Delay * 1000)
|
||||
// LEDRGB = info.LEDInfos[i].LEDRGB;
|
||||
// else
|
||||
// break;
|
||||
// }
|
||||
// info.Copter.LEDColor = LEDRGB;
|
||||
//
|
||||
// }
|
||||
|
||||
if (info.LEDInfos.Count > 0)
|
||||
{
|
||||
string LEDRGB = "";
|
||||
List<LEDInfo> LedControl = info.LEDInfos.OrderBy(i=>i.Delay).ToList();
|
||||
List<LEDInfo> LedControl = info.LEDInfos.ToList();
|
||||
double time = 0;
|
||||
for (int i = 0; i < LedControl.Count; i++)
|
||||
{
|
||||
|
||||
var led = LedControl[i];
|
||||
if (ts.TotalMilliseconds >= led.Delay * 1000)
|
||||
time += led.Delay * 1000;
|
||||
if (ts.TotalMilliseconds >= time)
|
||||
LEDRGB = info.LEDInfos[i].LEDRGB;
|
||||
else
|
||||
break;
|
||||
@ -205,7 +224,7 @@ namespace Plane.FormationCreator.Formation
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (ts.TotalMilliseconds / 10 > sendFlyToTimes) // 每500ms发送一遍指点坐标
|
||||
{
|
||||
|
@ -37,8 +37,8 @@
|
||||
|
||||
|
||||
</c:MetroWindow.Resources>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<c:MetroWindow.RightWindowCommands>
|
||||
<c:WindowCommands>
|
||||
@ -73,23 +73,28 @@
|
||||
<Button Name="btnConnect"
|
||||
Content="连接"
|
||||
Click="btnConnect_Click" />
|
||||
<Menu Name="menuTask" VerticalAlignment="Center" >
|
||||
<Menu Name="menuTask" Background="Transparent" VerticalAlignment="Center" >
|
||||
|
||||
<MenuItem Header="导入导出" Margin="0,2,0,0" Foreground="#969696">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
|
||||
<Button BorderThickness="1" Content="导出任务" Margin="0,8,0,8"
|
||||
Command="{Binding ExportTasksCommand}"/>
|
||||
<CheckBox Content="只导出航点" Grid.Column="1" Margin="0,8,0,8" Foreground="#969696"
|
||||
IsChecked="{Binding OnlyImpotWaypointS}"/>
|
||||
<Button BorderThickness="1" BorderBrush="#FFFFFF" Content="导入任务" Margin="0,8,0,8" Grid.Row="1"
|
||||
Command="{Binding ImportTasksCommand}"></Button>
|
||||
Command="{Binding ImportTasksCommand}"/>
|
||||
<StackPanel VerticalAlignment="Center" Margin="0,8,0,8" Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock Foreground="#969696" VerticalAlignment="Center" Text="起始步骤:"/>
|
||||
<TextBox VerticalAlignment="Bottom" Width="40"
|
||||
@ -98,13 +103,17 @@
|
||||
<TextBox VerticalAlignment="Bottom" Width="40"
|
||||
Text="{Binding txtendindex, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</StackPanel>
|
||||
<Button BorderThickness="1" BorderBrush="#FFFFFF" Content="导入摆放位置" Margin="25,8,0,8" Grid.Row="2"
|
||||
Command="{Binding ImportTasksCommand}"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
</MenuItem>
|
||||
|
||||
|
||||
</Menu>
|
||||
|
||||
<Menu Name="otherWindows" Background="Transparent" VerticalAlignment="Center">
|
||||
<MenuItem Header="窗口" Margin="0,2,0,0" Foreground="#969696">
|
||||
<CheckBox Content="属性设置" Margin="0,8,0,8" IsChecked="False" Click="btnAttribute_Click"/>
|
||||
<CheckBox Content="分组设置" Margin="0,8,0,8" IsChecked="False" Click="btnGroup_Click"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</c:WindowCommands>
|
||||
</c:MetroWindow.RightWindowCommands>
|
||||
@ -132,8 +141,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
|
||||
<TabControl SelectedIndex="{Binding MapMode,UpdateSourceTrigger=PropertyChanged}">
|
||||
<TabControl SelectedIndex="{Binding MapMode,UpdateSourceTrigger=PropertyChanged}" Grid.RowSpan="3">
|
||||
<TabItem Visibility="Collapsed">
|
||||
<v:MapView x:Name="map"/>
|
||||
</TabItem >
|
||||
@ -142,15 +150,28 @@
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
|
||||
<Grid Grid.Row="1" HorizontalAlignment="Right">
|
||||
<WrapPanel Orientation="Vertical">
|
||||
<v:CopterAttributeView
|
||||
x:Name="attributeView"
|
||||
Visibility="Collapsed"
|
||||
DataContext="{Binding Path=CopterListViewModel}">
|
||||
</v:CopterAttributeView>
|
||||
<v:CopterGroupsView
|
||||
x:Name="groupsView"
|
||||
Visibility="Collapsed">
|
||||
</v:CopterGroupsView>
|
||||
</WrapPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
<!--
|
||||
<v:MapView x:Name="map"/>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
<v:TaskBarView
|
||||
Grid.Row="2"
|
||||
x:Name="TaskbarControl"
|
||||
VerticalAlignment="Bottom"
|
||||
Visibility="{Binding Source={x:Static local:AppEx.Current}, Path=AppMode, Converter={StaticResource AppModeToVisibilityConverter}, ConverterParameter=TaskBarView}" />
|
||||
@ -169,18 +190,12 @@
|
||||
<v:CopterListView />
|
||||
|
||||
<StackPanel Grid.Row="1">
|
||||
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Visibility="{Binding AppEx.ShowModifyTaskView, Converter={StaticResource InversiveBooleanToVisibilityConverter}}">
|
||||
|
||||
<Separator Grid.ColumnSpan="2" />
|
||||
<v:ControlPanelView />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
<StackPanel Visibility="{Binding AppEx.ShowModifyTaskView, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Separator />
|
||||
<v:ModifyTaskView />
|
||||
|
@ -507,5 +507,23 @@ namespace Plane.FormationCreator
|
||||
map.Opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnAttribute_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CheckBox checkbox = sender as CheckBox;
|
||||
if (checkbox.IsChecked == false)
|
||||
attributeView.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
attributeView.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void btnGroup_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CheckBox checkbox = sender as CheckBox;
|
||||
if (checkbox.IsChecked == false)
|
||||
groupsView.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
groupsView.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,6 +174,7 @@
|
||||
<Compile Include="Formation\FlightTask_Turn.cs" />
|
||||
<Compile Include="Formation\FormationController.cs" />
|
||||
<Compile Include="Formation\CopterManager.cs" />
|
||||
<Compile Include="Formation\GroupManager.cs" />
|
||||
<Compile Include="Formation\LatLng.cs" />
|
||||
<Compile Include="Formation\MapManager.cs" />
|
||||
<Compile Include="Formation\MapServer.cs" />
|
||||
@ -196,6 +197,7 @@
|
||||
<Compile Include="ViewModels\ConnectViewModel.cs" />
|
||||
<Compile Include="ViewModels\ControlPanelViewModel.cs" />
|
||||
<Compile Include="ViewModels\CopterListViewModel.cs" />
|
||||
<Compile Include="ViewModels\GroupsViewModel.cs" />
|
||||
<Compile Include="ViewModels\MainViewModel.cs" />
|
||||
<Compile Include="ViewModels\MapViewModel.cs" />
|
||||
<Compile Include="ViewModels\ModifyTaskViewModel.cs" />
|
||||
@ -208,6 +210,12 @@
|
||||
<Compile Include="Views\ControlPanelView.xaml.cs">
|
||||
<DependentUpon>ControlPanelView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CopterAttributeView.xaml.cs">
|
||||
<DependentUpon>CopterAttributeView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CopterGroupsView.xaml.cs">
|
||||
<DependentUpon>CopterGroupsView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\CopterInfoView.xaml.cs">
|
||||
<DependentUpon>CopterInfoView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -325,6 +333,14 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\CopterAttributeView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\CopterGroupsView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\CopterInfoView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -34,9 +34,11 @@ namespace Plane.FormationCreator
|
||||
_container.Register<View3DViewModel>();
|
||||
_container.Register<ModifyTaskViewModel>();
|
||||
_container.Register<CalibrationViewModel>();
|
||||
_container.Register<GroupsViewModel>();
|
||||
|
||||
_container.Register<ILogger>(() => new LocalFileLogger(new DebugLogger()));
|
||||
|
||||
_container.Register<GroupManager>();
|
||||
_container.Register<CopterManager>();
|
||||
_container.Register<MapManager>();
|
||||
_container.Register<View3DManager>();
|
||||
|
@ -159,7 +159,7 @@ namespace Plane.FormationCreator.ViewModels
|
||||
await commModule.DoCalibrationCompassAsync(_copterManager.SelectedCopters);
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
|
||||
/*
|
||||
/*支持多飞行机同时校准 不再判断单架的返回值
|
||||
|
||||
IsCalibration = true;
|
||||
CompassPercent = 0;
|
||||
|
@ -125,6 +125,13 @@ namespace Plane.FormationCreator.ViewModels
|
||||
set { Set(nameof(CopterNum), ref _CopterNum, value); }
|
||||
}
|
||||
|
||||
private string _CopterColor = "";
|
||||
public string CopterColor
|
||||
{
|
||||
get { return _CopterColor; }
|
||||
set { Set(nameof(CopterColor), ref _CopterColor, value); }
|
||||
}
|
||||
|
||||
private ICommand _WriteIdCommand;
|
||||
public ICommand WriteIdCommand
|
||||
{
|
||||
@ -215,7 +222,7 @@ namespace Plane.FormationCreator.ViewModels
|
||||
{
|
||||
return _CommDataAsync ?? (_CommDataAsync = new RelayCommand(async () =>
|
||||
{
|
||||
await commModule.TestLED((short)CopterNum);
|
||||
await commModule.TestLED((short)CopterNum, CopterColor);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
@ -978,7 +978,7 @@ namespace Plane.FormationCreator.ViewModels
|
||||
int utcsecond = DateTime.UtcNow.AddSeconds(5).Second;
|
||||
Message.Show("开始任务");
|
||||
//循环3次 发送起飞命令 避免通信问题
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _commModuleManager.DoMissionStartAsync(utchour,
|
||||
utcminute,
|
||||
@ -1001,6 +1001,7 @@ namespace Plane.FormationCreator.ViewModels
|
||||
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
}
|
||||
Alert.Show("所有飞机开始执行航点任务。请勿多次开始任务!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -1144,10 +1145,12 @@ namespace Plane.FormationCreator.ViewModels
|
||||
/// <returns></returns>
|
||||
private async Task CollectMissions(int i)
|
||||
{
|
||||
float groudAlt = _copterManager.Copters[i].GroundAlt;
|
||||
var missions = new List<IMission>();
|
||||
var _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
|
||||
for (int j = 0; j < _flightTaskManager.Tasks.Count; j++)
|
||||
{
|
||||
|
||||
switch (_flightTaskManager.Tasks[j].TaskType)
|
||||
{
|
||||
case FlightTaskType.TakeOff:
|
||||
@ -1158,11 +1161,12 @@ namespace Plane.FormationCreator.ViewModels
|
||||
_flightTaskManager.Tasks[j].TakeOffTime,
|
||||
_flightTaskManager.Tasks[j + 1].SingleCopterInfos[i].TargetLat - _flightTaskManager.OriginLat,
|
||||
_flightTaskManager.Tasks[j + 1].SingleCopterInfos[i].TargetLng - _flightTaskManager.OriginLng,
|
||||
_flightTaskManager.Tasks[j + 1].SingleCopterInfos[i].TargetAlt)
|
||||
_flightTaskManager.Tasks[j + 1].SingleCopterInfos[i].TargetAlt - groudAlt)
|
||||
);
|
||||
break;
|
||||
|
||||
case FlightTaskType.FlyTo:
|
||||
|
||||
missions.AddRange(CreateLEDMissions(_flightTaskManager.Tasks[j].SingleCopterInfos[i].LEDInfos));
|
||||
if (_flightTaskManager.Tasks[j].SingleCopterInfos[i].IsChangeSpeed)
|
||||
{
|
||||
@ -1179,12 +1183,13 @@ namespace Plane.FormationCreator.ViewModels
|
||||
Lat = 90;
|
||||
Lng = 180;
|
||||
}
|
||||
|
||||
missions.Add(Mission.CreateWaypointMission(
|
||||
_flightTaskManager.Tasks[j].LoiterTime,
|
||||
_flightTaskManager.Tasks[j].FlytoTime,
|
||||
Lat,
|
||||
Lng,
|
||||
_flightTaskManager.Tasks[j].SingleCopterInfos[i].TargetAlt)
|
||||
_flightTaskManager.Tasks[j].SingleCopterInfos[i].TargetAlt - groudAlt)
|
||||
);
|
||||
break;
|
||||
case FlightTaskType.Loiter:
|
||||
|
@ -17,16 +17,20 @@ using Plane.Communication;
|
||||
using Plane.Geography;
|
||||
using Microsoft.Practices.ServiceLocation;
|
||||
using Plane.FormationCreator.Util;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Plane.FormationCreator.ViewModels
|
||||
{
|
||||
public class CopterListViewModel : ViewModelBase
|
||||
{
|
||||
public CopterListViewModel(CopterManager copterManager, MapManager mapManager, FlightTaskManager flightTaskManager)
|
||||
public CopterListViewModel(CopterManager copterManager, MapManager mapManager, FlightTaskManager flightTaskManager, GroupManager groupManager)
|
||||
{
|
||||
_copterManager = copterManager;
|
||||
_mapManager = mapManager;
|
||||
_flightTaskManager = flightTaskManager;
|
||||
_groupManager = groupManager;
|
||||
/*
|
||||
System.Timers.Timer t = new System.Timers.Timer(5000); //实例化Timer类,设置间隔时间为1秒;
|
||||
t.Elapsed += new System.Timers.ElapsedEventHandler(theout); //到达时间的时候执行事件;
|
||||
@ -55,12 +59,14 @@ namespace Plane.FormationCreator.ViewModels
|
||||
allsend / _copterManager.Copters.Count+"/s";
|
||||
}
|
||||
|
||||
private GroupManager _groupManager;
|
||||
private CopterManager _copterManager;
|
||||
private MapManager _mapManager;
|
||||
private FlightTaskManager _flightTaskManager;
|
||||
private View3DManager _view3DManager = ServiceLocator.Current.GetInstance<View3DManager>();
|
||||
|
||||
|
||||
public CopterManager CopterManager { get { return _copterManager; } }
|
||||
|
||||
|
||||
private ICopter _SelectedCopter;
|
||||
public ICopter SelectedCopter
|
||||
@ -93,7 +99,9 @@ namespace Plane.FormationCreator.ViewModels
|
||||
set { Set(nameof(ContinuousNum), ref _ContinuousNum, value); }
|
||||
}
|
||||
|
||||
|
||||
public ObservableCollection<string[]> CopterGroups { get; } = new ObservableCollection<string[]>();
|
||||
|
||||
|
||||
|
||||
private ICommand _IntervalSelectCoptersCommand;
|
||||
public ICommand IntervalSelectCoptersCommand
|
||||
@ -296,7 +304,128 @@ namespace Plane.FormationCreator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
// private ICommand _ImportCoptersLocationCommand;
|
||||
// public ICommand ImportCoptersLocationCommand
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return _ImportCoptersLocationCommand ?? (_ImportCoptersLocationCommand = new RelayCommand(async() =>
|
||||
// {
|
||||
// var dialog = new Microsoft.Win32.OpenFileDialog
|
||||
// {
|
||||
// DefaultExt = "json",
|
||||
// Filter = "编队飞行任务 (*.json)|*.json"
|
||||
// };
|
||||
// if (dialog.ShowDialog() == true)
|
||||
// {
|
||||
// var locationsText = File.ReadAllText(dialog.FileName);
|
||||
// dynamic coptersLocation = JsonConvert.DeserializeObject(locationsText);
|
||||
// foreach (var location in coptersLocation)
|
||||
// {
|
||||
// var name = location.Name;
|
||||
// JArray locations = location.Value as JArray;
|
||||
// var x = ((Newtonsoft.Json.Linq.JValue)(locations[0])).Value;
|
||||
// float fx = Convert.ToSingle(x);
|
||||
// var y = ((Newtonsoft.Json.Linq.JValue)(locations[1])).Value;
|
||||
// float fy = Convert.ToSingle(y);
|
||||
//
|
||||
// var fc = _copterManager.Copters[int.Parse(name) - 1] as FakeCopter;
|
||||
// Tuple<double, double> observationLatLng = null;
|
||||
// observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
// _flightTaskManager.OriginLat,
|
||||
// _flightTaskManager.OriginLng,
|
||||
// 90,
|
||||
// fx);
|
||||
//
|
||||
//
|
||||
// observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
// observationLatLng.Item1,
|
||||
// observationLatLng.Item2,
|
||||
// 0,
|
||||
// fy);
|
||||
//
|
||||
// fc.SetProperties(
|
||||
// latitude: observationLatLng.Item1,
|
||||
// longitude: observationLatLng.Item2
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// await Task.Delay(10);
|
||||
// }));
|
||||
// }
|
||||
// }
|
||||
|
||||
private ICommand _ImportCoptersLocationCommand;
|
||||
public ICommand ImportCoptersLocationCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ImportCoptersLocationCommand ?? (_ImportCoptersLocationCommand = new RelayCommand(async () =>
|
||||
{
|
||||
var dialog = new Microsoft.Win32.OpenFileDialog
|
||||
{
|
||||
DefaultExt = "txt",
|
||||
Filter = "编队飞行任务 (*.json)|*.txt"
|
||||
};
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
var locationsText = File.ReadAllText(dialog.FileName);
|
||||
string[] coptersLocation = locationsText.Replace("\r\n","\n").Split('\n');
|
||||
foreach (var location in coptersLocation)
|
||||
{
|
||||
string[] locations = location.Split(' ');
|
||||
var name = locations[0];
|
||||
|
||||
var x = locations[2];
|
||||
float fx = Convert.ToSingle(x)/100;
|
||||
var y = locations[4];
|
||||
float fy = Convert.ToSingle(y)/100;
|
||||
|
||||
var fc = _copterManager.Copters[int.Parse(name)] as FakeCopter;
|
||||
Tuple<double, double> observationLatLng = null;
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
_flightTaskManager.OriginLat,
|
||||
_flightTaskManager.OriginLng,
|
||||
90,
|
||||
fx);
|
||||
|
||||
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
observationLatLng.Item1,
|
||||
observationLatLng.Item2,
|
||||
0,
|
||||
fy);
|
||||
|
||||
fc.SetProperties(
|
||||
latitude: observationLatLng.Item1,
|
||||
longitude: observationLatLng.Item2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _ApplyGroundAltCommand;
|
||||
public ICommand ApplyGroundAltCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ApplyGroundAltCommand ?? (_ApplyGroundAltCommand = new RelayCommand(async () =>
|
||||
{
|
||||
|
||||
foreach (var copter in _copterManager.SelectedCopters)
|
||||
{
|
||||
copter.GroundAlt = SelectedCopter.GroundAlt;
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using System.Windows.Input;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Practices.ServiceLocation;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Plane.FormationCreator.ViewModels
|
||||
{
|
||||
@ -32,6 +33,9 @@ namespace Plane.FormationCreator.ViewModels
|
||||
private CopterListViewModel _copterListViewModel;
|
||||
public CopterListViewModel CopterListViewModel { get { return _copterListViewModel; } }
|
||||
private FlightTaskManager _flightTaskManager = ServiceLocator.Current.GetInstance<FlightTaskManager>();
|
||||
private GroupManager _groupManager = ServiceLocator.Current.GetInstance<GroupManager>();
|
||||
private CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
|
||||
|
||||
public AppEx AppEx { get; } = AppEx.Current;
|
||||
|
||||
private void AppEx_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
@ -171,7 +175,12 @@ namespace Plane.FormationCreator.ViewModels
|
||||
}
|
||||
|
||||
|
||||
|
||||
private bool _OnlyImpotWaypointS = true;
|
||||
public bool OnlyImpotWaypointS
|
||||
{
|
||||
get { return _OnlyImpotWaypointS; }
|
||||
set { Set(nameof(OnlyImpotWaypointS), ref _OnlyImpotWaypointS, value); }
|
||||
}
|
||||
|
||||
private ICommand _ExportTasksCommand;
|
||||
public ICommand ExportTasksCommand
|
||||
@ -185,7 +194,28 @@ namespace Plane.FormationCreator.ViewModels
|
||||
Alert.Show("作为参照的原点未设置,无法导出相对位置!", "提示");
|
||||
return;
|
||||
}
|
||||
var exportedText = _flightTaskManager.ExportTasks();
|
||||
|
||||
string exportedText;
|
||||
|
||||
var taskObject = _flightTaskManager.ExportTasks();
|
||||
if (OnlyImpotWaypointS)
|
||||
{
|
||||
exportedText = JsonConvert.SerializeObject(taskObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
var groupObject = _groupManager.ExportGroups();
|
||||
var locateObject = ExportLocate();
|
||||
object obj = new
|
||||
{
|
||||
groups = groupObject,
|
||||
locate = locateObject,
|
||||
tasks = taskObject
|
||||
};
|
||||
exportedText = JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
|
||||
|
||||
var dialog = new SaveFileDialog
|
||||
{
|
||||
DefaultExt = "fcg",
|
||||
@ -199,6 +229,20 @@ namespace Plane.FormationCreator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private List<object> ExportLocate()
|
||||
{
|
||||
List<object> locateList = new List<object>();
|
||||
foreach (var copter in _copterManager.Copters)
|
||||
{
|
||||
double[] locate = new double[3];
|
||||
locate[0] = copter.Latitude - _flightTaskManager.OriginLat;
|
||||
locate[1] = copter.Longitude - _flightTaskManager.OriginLng;
|
||||
locate[2] = copter.GroundAlt;
|
||||
locateList.Add(locate);
|
||||
}
|
||||
return locateList;
|
||||
}
|
||||
|
||||
|
||||
private int _txtStarindex = 0;
|
||||
public int txtStarindex
|
||||
@ -236,9 +280,32 @@ namespace Plane.FormationCreator.ViewModels
|
||||
int _startindex = txtStarindex;
|
||||
int _endindex = txtendindex;
|
||||
|
||||
var tasksText = File.ReadAllText(dialog.FileName);
|
||||
var importText = File.ReadAllText(dialog.FileName);
|
||||
|
||||
dynamic importInfo = JsonConvert.DeserializeObject(importText);
|
||||
dynamic taskinfo = null;
|
||||
if (importInfo is Newtonsoft.Json.Linq.JObject)
|
||||
{
|
||||
taskinfo = importInfo.tasks;
|
||||
if (importInfo.locate != null)
|
||||
{
|
||||
//ImportCoptersLocate(importInfo.locate);
|
||||
}
|
||||
if (importInfo.groups != null)
|
||||
{
|
||||
_groupManager.ImportGroupsInfo(importInfo.groups);
|
||||
}
|
||||
}
|
||||
else if (importInfo is Newtonsoft.Json.Linq.JArray)
|
||||
{
|
||||
taskinfo = importInfo;
|
||||
}
|
||||
|
||||
if ((txtStarindex == 0) && (txtendindex == 0))
|
||||
_flightTaskManager.ImportTasks(tasksText);
|
||||
{
|
||||
|
||||
_flightTaskManager.ImportTasks(taskinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
_endindex = txtendindex;
|
||||
@ -246,7 +313,7 @@ namespace Plane.FormationCreator.ViewModels
|
||||
_startindex = 1;
|
||||
if (_endindex == 0)
|
||||
_endindex = _startindex;
|
||||
_flightTaskManager.ImportTasksindex(tasksText, _startindex, _endindex);
|
||||
_flightTaskManager.ImportTasksindex(taskinfo, _startindex, _endindex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -521,9 +521,8 @@ namespace Plane.FormationCreator.ViewModels
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
var tasksText = File.ReadAllText(dialog.FileName);
|
||||
|
||||
_flightTaskManager.ImportBlenderFlyToTask(tasksText);
|
||||
|
||||
_flightTaskManager.ImportC4DFlytoTask(tasksText);
|
||||
//_flightTaskManager.ImportBlenderFlyToTask(tasksText);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@ -926,9 +925,10 @@ public ICommand VerticlAlignmentCommand
|
||||
|
||||
if (_copterManager.Copters.Count > 0)
|
||||
{
|
||||
centlng = _copterManager.Copters[0].Longitude;
|
||||
centlat = _copterManager.Copters[0].Latitude;
|
||||
|
||||
//centlng = _copterManager.Copters[0].Longitude;
|
||||
//centlat = _copterManager.Copters[0].Latitude;
|
||||
centlng = _flightTaskManager.OriginLng;
|
||||
centlat = _flightTaskManager.OriginLat;
|
||||
//虚拟飞机一起旋转
|
||||
if ("FakeCopter" == _copterManager.Copters[0].GetType().Name)
|
||||
{
|
||||
@ -1517,8 +1517,11 @@ public ICommand VerticlAlignmentCommand
|
||||
{
|
||||
LEDInfo endLed = new LEDInfo();
|
||||
endLed.LEDMode = 0;
|
||||
endLed.Delay = BeginTime + (time + 1) * (EndTime - BeginTime) / AverageSum;
|
||||
endLed.LEDRGB = EndRGB;
|
||||
endLed.Delay = (EndTime - BeginTime) / AverageSum;
|
||||
if (EndRGB == "0")
|
||||
endLed.LEDRGB = copterInfo.LEDInfos[copterInfo.LEDInfos.Count - 2].LEDRGB;
|
||||
else
|
||||
endLed.LEDRGB = EndRGB;
|
||||
copterInfo.AddLEDInfo(endLed);
|
||||
}
|
||||
}
|
||||
@ -1585,9 +1588,21 @@ public ICommand VerticlAlignmentCommand
|
||||
LEDInfo led = new LEDInfo();
|
||||
led.LEDMode = 0;
|
||||
led.Delay = curTime;
|
||||
led.LEDRGB = StrokesRGB;
|
||||
led.LEDRGB = ChangeRGB;
|
||||
copterInfo.AddLEDInfo(led);
|
||||
|
||||
if (EndRGB != "")
|
||||
{
|
||||
LEDInfo endLed = new LEDInfo();
|
||||
endLed.LEDMode = 0;
|
||||
endLed.Delay = IntervalTime;
|
||||
if (EndRGB == "0")
|
||||
endLed.LEDRGB = copterInfo.LEDInfos[copterInfo.LEDInfos.Count - 2].LEDRGB;
|
||||
else
|
||||
endLed.LEDRGB = EndRGB;
|
||||
copterInfo.AddLEDInfo(endLed);
|
||||
}
|
||||
|
||||
curcount++;
|
||||
}
|
||||
|
||||
|
@ -103,15 +103,18 @@ namespace Plane.FormationCreator.ViewModels
|
||||
|
||||
private void AddOrMove3DCopter(ICopter copter)
|
||||
{
|
||||
var copternum1 = _copterManager.Copters.FirstOrDefault();
|
||||
//var copternum1 = _copterManager.Copters.FirstOrDefault();
|
||||
if (_flightTaskManager.OriginLat == 0 || _flightTaskManager.OriginLng == 0)
|
||||
return;
|
||||
|
||||
//第一列到中间的距离
|
||||
float midColDistance = (_flightTaskManager.ColumnCount - 1) * _flightTaskManager.ColumnDistance / 2;
|
||||
|
||||
if (observationLatLng == null)
|
||||
{
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
copternum1.Latitude,
|
||||
copternum1.Longitude,
|
||||
_flightTaskManager.OriginLat,
|
||||
_flightTaskManager.OriginLng,
|
||||
_flightTaskManager.Orientation + 90,
|
||||
midColDistance);
|
||||
observationLatLng = GeographyUtils.CalcLatLngSomeMetersAway2D(
|
||||
|
@ -145,7 +145,8 @@
|
||||
<TextBox Margin="2,5,5,5" Width="30" Text="{Binding CopterNum}"></TextBox>
|
||||
<Button Content=" 对频 " Margin="5,5,0,5" Command="{Binding Path=WriteIdCommand}" />
|
||||
<Button Content="闪灯" Margin="5" Command="{Binding CommDataAsync}"/>
|
||||
|
||||
<TextBox Width="80" Text="{Binding CopterColor}"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
|
@ -87,6 +87,9 @@
|
||||
VerticalContentAlignment="Center"
|
||||
Command="{Binding AddVirtualCopterCommand}"
|
||||
CommandParameter="{Binding Text, ElementName=txtVirtualCopterCount}" />
|
||||
<Button Content="导入飞机位置"
|
||||
Margin="5,0,0,0"
|
||||
Command="{Binding ImportCoptersLocationCommand}"/>
|
||||
<Button Content="清除"
|
||||
Margin="5,0,0,0"
|
||||
Command="{Binding ClearCoptersCommand}" />
|
||||
|
@ -40,7 +40,7 @@ namespace Plane.FormationCreator.Views
|
||||
lvwDrones.ScrollIntoView(lvwDrones.SelectedItem);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private CopterManager _copterManager = ServiceLocator.Current.GetInstance<CopterManager>();
|
||||
private void SelectitemMessage(ICopter copter)
|
||||
{
|
||||
|
@ -67,6 +67,7 @@ namespace Plane.FormationCreator.Views
|
||||
{
|
||||
if (Dispatcher.Invoke(RemoveLoadingErrorMessage))
|
||||
{
|
||||
|
||||
delay = 2000;
|
||||
}
|
||||
await Task.Delay(delay);
|
||||
|
@ -39,20 +39,31 @@
|
||||
</StackPanel>
|
||||
|
||||
<Separator />
|
||||
<Grid DataContext="{Binding FlightTaskManager.SelectedTask.ModifyingSingleCopterInfo}"
|
||||
>
|
||||
<Grid DataContext="{Binding FlightTaskManager.SelectedTask.ModifyingSingleCopterInfo}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Margin="5" Text="起飞延时"/>
|
||||
<TextBox Margin="5" Grid.Column="2"
|
||||
Text="{Binding TakeOffWaitTime, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="应用所选" Margin="5" Grid.Column="3"
|
||||
Command="{Binding SetSelTakeOffWaitCommand}"/>
|
||||
<Separator Grid.Row="1" Grid.ColumnSpan="4"/>
|
||||
|
||||
<TextBlock Text="随机时间" Grid.Row="2"/>
|
||||
<TextBox Margin="10,0" Grid.Row="2" Grid.Column="1" Text="{Binding TakeOffMinTime}"/>
|
||||
<TextBox Margin="10,0" Grid.Row="2" Grid.Column="2" Text="{Binding TakeOffMaxTime}"/>
|
||||
<Button Margin="10,0" Content="应用所选" Grid.Row="2" Grid.Column="3"
|
||||
Command="{Binding SetRandomOffWaitDelayCommand}"/>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
@ -311,8 +322,7 @@
|
||||
<TextBox Margin="5,5,0,3" Width="30" Text="{Binding IntervalTime}"/>
|
||||
<TextBlock Margin="5,7,0,0" Text="变换数量"/>
|
||||
<TextBox Margin="5,5,0,3" Width="30" Text="{Binding SingleNum}"/>
|
||||
<TextBlock Margin="5,7,0,0" Text="颜色"/>
|
||||
<TextBox Margin="5,5,0,3" Width="60" Text="{Binding StrokesRGB}"/>
|
||||
|
||||
<Button Width="70" Content="灯光"
|
||||
Command="{Binding SetStrokesLampCommamd}" HorizontalAlignment="Right"/>
|
||||
</StackPanel>
|
||||
@ -430,5 +440,6 @@
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
</TabControl>
|
||||
</UserControl>
|
||||
|
Loading…
Reference in New Issue
Block a user