diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs
index a43aa89..905b85a 100644
--- a/Torch.API/ITorchBase.cs
+++ b/Torch.API/ITorchBase.cs
@@ -74,12 +74,17 @@ namespace Torch.API
/// Stop the Torch instance.
///
void Stop();
-
+
+ ///
+ /// Restart the Torch instance.
+ ///
+ void Restart();
+
///
/// Initializes a save of the game.
///
/// Id of the player who initiated the save.
- void Save(long callerId);
+ Task Save(long callerId);
///
/// Initialize the Torch instance.
diff --git a/Torch.API/Managers/IPluginManager.cs b/Torch.API/Managers/IPluginManager.cs
index a1ad100..2a0d729 100644
--- a/Torch.API/Managers/IPluginManager.cs
+++ b/Torch.API/Managers/IPluginManager.cs
@@ -14,12 +14,12 @@ namespace Torch.API.Managers
///
/// Fired when plugins are loaded.
///
- event Action> PluginsLoaded;
+ event Action> PluginsLoaded;
///
/// Collection of loaded plugins.
///
- ObservableCollection Plugins { get; }
+ IList Plugins { get; }
///
/// Updates all loaded plugins.
diff --git a/Torch.Client/Properties/AssemblyInfo.cs b/Torch.Client/Properties/AssemblyInfo.cs
index 0b06134..43cfce9 100644
--- a/Torch.Client/Properties/AssemblyInfo.cs
+++ b/Torch.Client/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("1.0.186.642")]
-[assembly: AssemblyFileVersion("1.0.186.642")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.195.514")]
+[assembly: AssemblyFileVersion("1.0.195.514")]
\ No newline at end of file
diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs
index ecf9a3f..17fb1e0 100644
--- a/Torch.Server/Program.cs
+++ b/Torch.Server/Program.cs
@@ -100,6 +100,8 @@ namespace Torch.Server
var waitProc = Process.GetProcessById(pid);
_log.Warn($"Waiting for process {pid} to exit.");
waitProc.WaitForExit();
+ _log.Info("Continuing in 5 seconds.");
+ Thread.Sleep(5000);
}
catch
{
@@ -245,8 +247,8 @@ quit";
}*/
_server = new TorchServer(config);
- _server.Init();
+ _server.Init();
if (config.NoGui || config.Autostart)
{
new Thread(() => _server.Start()).Start();
@@ -255,7 +257,6 @@ quit";
if (!config.NoGui)
{
var ui = new TorchUI((TorchServer)_server);
- ui.LoadConfig(config);
ui.ShowDialog();
}
}
diff --git a/Torch.Server/Properties/AssemblyInfo.cs b/Torch.Server/Properties/AssemblyInfo.cs
index 0b06134..43cfce9 100644
--- a/Torch.Server/Properties/AssemblyInfo.cs
+++ b/Torch.Server/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("1.0.186.642")]
-[assembly: AssemblyFileVersion("1.0.186.642")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.195.514")]
+[assembly: AssemblyFileVersion("1.0.195.514")]
\ No newline at end of file
diff --git a/Torch.Server/TorchConfig.cs b/Torch.Server/TorchConfig.cs
index 16d37a4..e3268d4 100644
--- a/Torch.Server/TorchConfig.cs
+++ b/Torch.Server/TorchConfig.cs
@@ -24,7 +24,7 @@ namespace Torch.Server
public bool Update { get; set; }
///
- [XmlIgnore, Arg("autostart", "Start the server immediately.")]
+ [Arg("autostart", "Start the server immediately.")]
public bool Autostart { get; set; }
///
@@ -32,7 +32,7 @@ namespace Torch.Server
public bool RestartOnCrash { get; set; }
///
- [XmlIgnore, Arg("nogui", "Do not show the Torch UI.")]
+ [Arg("nogui", "Do not show the Torch UI.")]
public bool NoGui { get; set; }
///
diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs
index 813d413..3cd8298 100644
--- a/Torch.Server/TorchServer.cs
+++ b/Torch.Server/TorchServer.cs
@@ -10,6 +10,7 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Principal;
using System.Threading;
+using System.Threading.Tasks;
using Microsoft.Xml.Serialization.GeneratedAssembly;
using Sandbox.Engine.Analytics;
using Sandbox.Game.Multiplayer;
@@ -20,6 +21,7 @@ using Torch.Managers;
using VRage.Dedicated;
using VRage.FileSystem;
using VRage.Game;
+using VRage.Game.ModAPI;
using VRage.Game.ObjectBuilder;
using VRage.Game.SessionComponents;
using VRage.Library;
@@ -49,6 +51,7 @@ namespace Torch.Server
private float _simRatio;
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
private Timer _watchdog;
+ private Stopwatch _uptime;
public TorchServer(TorchConfig config = null)
{
@@ -133,6 +136,7 @@ namespace Torch.Server
if (State != ServerState.Stopped)
return;
+ _uptime = Stopwatch.StartNew();
IsRunning = true;
GameThread = Thread.CurrentThread;
Config.Save();
@@ -166,7 +170,8 @@ namespace Torch.Server
{
base.Update();
SimulationRatio = Sync.ServerSimulationRatio;
- ElapsedPlayTime = MySession.Static?.ElapsedPlayTime ?? default(TimeSpan);
+ var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
+ ElapsedPlayTime = elapsed;
if (_watchdog == null && Instance.Config.TickTimeout > 0)
{
@@ -215,15 +220,21 @@ namespace Torch.Server
IsRunning = false;
}
- public void Restart()
+ ///
+ /// Restart the program. DOES NOT SAVE!
+ ///
+ public override void Restart()
{
-
+ var exe = Assembly.GetExecutingAssembly().Location;
+ ((TorchConfig)Config).WaitForPID = Process.GetCurrentProcess().Id.ToString();
+ Process.Start(exe, Config.ToString());
+ Environment.Exit(0);
}
///
- public override void Save(long callerId)
+ public override Task Save(long callerId)
{
- base.SaveGameAsync((statusCode) => SaveCompleted(statusCode, callerId));
+ return SaveGameAsync(statusCode => SaveCompleted(statusCode, callerId));
}
///
@@ -231,7 +242,7 @@ namespace Torch.Server
///
/// Return code of the save operation
/// Caller of the save operation
- private void SaveCompleted(SaveGameStatus statusCode, long callerId)
+ private void SaveCompleted(SaveGameStatus statusCode, long callerId = 0)
{
switch (statusCode)
{
diff --git a/Torch.Server/ViewModels/ConfigDedicatedViewModel.cs b/Torch.Server/ViewModels/ConfigDedicatedViewModel.cs
index e62862d..675089a 100644
--- a/Torch.Server/ViewModels/ConfigDedicatedViewModel.cs
+++ b/Torch.Server/ViewModels/ConfigDedicatedViewModel.cs
@@ -56,7 +56,7 @@ namespace Torch.Server.ViewModels
public SessionSettingsViewModel SessionSettings { get; }
- public ObservableCollection WorldPaths { get; } = new ObservableCollection();
+ public ObservableList WorldPaths { get; } = new ObservableList();
private string _administrators;
public string Administrators { get => _administrators; set { _administrators = value; OnPropertyChanged(); } }
private string _banned;
diff --git a/Torch.Server/ViewModels/Entities/Blocks/BlockViewModel.cs b/Torch.Server/ViewModels/Entities/Blocks/BlockViewModel.cs
index 56aa4ed..e3cbe76 100644
--- a/Torch.Server/ViewModels/Entities/Blocks/BlockViewModel.cs
+++ b/Torch.Server/ViewModels/Entities/Blocks/BlockViewModel.cs
@@ -15,7 +15,7 @@ namespace Torch.Server.ViewModels.Blocks
public class BlockViewModel : EntityViewModel
{
public IMyTerminalBlock Block { get; }
- public MTObservableCollection Properties { get; } = new MTObservableCollection();
+ public ObservableList Properties { get; } = new ObservableList();
public string FullName => $"{Block.CubeGrid.CustomName} - {Block.CustomName}";
@@ -24,8 +24,11 @@ namespace Torch.Server.ViewModels.Blocks
get => Block?.CustomName ?? "null";
set
{
- TorchBase.Instance.InvokeBlocking(() => Block.CustomName = value);
- OnPropertyChanged();
+ TorchBase.Instance.Invoke(() =>
+ {
+ Block.CustomName = value;
+ OnPropertyChanged();
+ });
}
}
@@ -37,8 +40,11 @@ namespace Torch.Server.ViewModels.Blocks
get => ((MySlimBlock)Block.SlimBlock).BuiltBy;
set
{
- TorchBase.Instance.InvokeBlocking(() => ((MySlimBlock)Block.SlimBlock).TransferAuthorship(value));
- OnPropertyChanged();
+ TorchBase.Instance.Invoke(() =>
+ {
+ ((MySlimBlock)Block.SlimBlock).TransferAuthorship(value);
+ OnPropertyChanged();
+ });
}
}
diff --git a/Torch.Server/ViewModels/Entities/Blocks/PropertyViewModel.cs b/Torch.Server/ViewModels/Entities/Blocks/PropertyViewModel.cs
index 95f709d..70eba37 100644
--- a/Torch.Server/ViewModels/Entities/Blocks/PropertyViewModel.cs
+++ b/Torch.Server/ViewModels/Entities/Blocks/PropertyViewModel.cs
@@ -16,17 +16,15 @@ namespace Torch.Server.ViewModels.Blocks
public T Value
{
- get
- {
- var val = default(T);
- TorchBase.Instance.InvokeBlocking(() => val = _prop.GetValue(Block.Block));
- return val;
- }
+ get => _prop.GetValue(Block.Block);
set
{
- TorchBase.Instance.InvokeBlocking(() => _prop.SetValue(Block.Block, value));
- OnPropertyChanged();
- Block.RefreshModel();
+ TorchBase.Instance.Invoke(() =>
+ {
+ _prop.SetValue(Block.Block, value);
+ OnPropertyChanged();
+ Block.RefreshModel();
+ });
}
}
diff --git a/Torch.Server/ViewModels/Entities/EntityViewModel.cs b/Torch.Server/ViewModels/Entities/EntityViewModel.cs
index 54e724b..80cae76 100644
--- a/Torch.Server/ViewModels/Entities/EntityViewModel.cs
+++ b/Torch.Server/ViewModels/Entities/EntityViewModel.cs
@@ -40,6 +40,7 @@ namespace Torch.Server.ViewModels.Entities
public EntityViewModel(IMyEntity entity, EntityTreeViewModel tree)
{
Entity = entity;
+ Tree = tree;
}
public EntityViewModel()
diff --git a/Torch.Server/ViewModels/Entities/GridViewModel.cs b/Torch.Server/ViewModels/Entities/GridViewModel.cs
index 3dd5363..fb55233 100644
--- a/Torch.Server/ViewModels/Entities/GridViewModel.cs
+++ b/Torch.Server/ViewModels/Entities/GridViewModel.cs
@@ -1,6 +1,9 @@
-using System.Linq;
+using System;
+using System.Linq;
using NLog;
using Sandbox.Game.Entities;
+using Sandbox.Game.Multiplayer;
+using Sandbox.Game.World;
using Sandbox.ModAPI;
using Torch.Server.ViewModels.Blocks;
@@ -9,17 +12,16 @@ namespace Torch.Server.ViewModels.Entities
public class GridViewModel : EntityViewModel, ILazyLoad
{
private MyCubeGrid Grid => (MyCubeGrid)Entity;
- public MTObservableCollection Blocks { get; } = new MTObservableCollection();
- private static readonly Logger Log = LogManager.GetLogger(nameof(GridViewModel));
+ public ObservableList Blocks { get; } = new ObservableList();
///
- public string DescriptiveName => $"{Name} ({Grid.BlocksCount} blocks)";
+ public string DescriptiveName { get; }
public GridViewModel() { }
public GridViewModel(MyCubeGrid grid, EntityTreeViewModel tree) : base(grid, tree)
{
- Log.Debug($"Creating model {Grid.DisplayName}");
+ DescriptiveName = $"{grid.DisplayName} ({grid.BlocksCount} blocks)";
Blocks.Add(new BlockViewModel(null, Tree));
}
@@ -28,7 +30,6 @@ namespace Torch.Server.ViewModels.Entities
if (obj.FatBlock != null)
Blocks.RemoveWhere(b => b.Block.EntityId == obj.FatBlock?.EntityId);
- Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
OnPropertyChanged(nameof(Name));
}
@@ -36,9 +37,8 @@ namespace Torch.Server.ViewModels.Entities
{
var block = obj.FatBlock as IMyTerminalBlock;
if (block != null)
- Blocks.Add(new BlockViewModel(block, Tree));
+ Blocks.Insert(new BlockViewModel(block, Tree), b => b.Name);
- Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
OnPropertyChanged(nameof(Name));
}
@@ -48,20 +48,23 @@ namespace Torch.Server.ViewModels.Entities
if (_load)
return;
- Log.Debug($"Loading model {Grid.DisplayName}");
_load = true;
Blocks.Clear();
- TorchBase.Instance.InvokeBlocking(() =>
+ TorchBase.Instance.Invoke(() =>
{
foreach (var block in Grid.GetFatBlocks().Where(b => b is IMyTerminalBlock))
{
Blocks.Add(new BlockViewModel((IMyTerminalBlock)block, Tree));
}
- });
- Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
- Grid.OnBlockAdded += Grid_OnBlockAdded;
- Grid.OnBlockRemoved += Grid_OnBlockRemoved;
+ Grid.OnBlockAdded += Grid_OnBlockAdded;
+ Grid.OnBlockRemoved += Grid_OnBlockRemoved;
+
+ Tree.ControlDispatcher.BeginInvoke(() =>
+ {
+ Blocks.Sort(b => b.Block.CustomName);
+ });
+ });
}
}
}
diff --git a/Torch.Server/ViewModels/Entities/VoxelMapViewModel.cs b/Torch.Server/ViewModels/Entities/VoxelMapViewModel.cs
index e19179a..36a6c1c 100644
--- a/Torch.Server/ViewModels/Entities/VoxelMapViewModel.cs
+++ b/Torch.Server/ViewModels/Entities/VoxelMapViewModel.cs
@@ -15,7 +15,7 @@ namespace Torch.Server.ViewModels.Entities
public override bool CanStop => false;
- public MTObservableCollection AttachedGrids { get; } = new MTObservableCollection();
+ public ObservableList AttachedGrids { get; } = new ObservableList();
public async Task UpdateAttachedGrids()
{
diff --git a/Torch.Server/ViewModels/EntityTreeViewModel.cs b/Torch.Server/ViewModels/EntityTreeViewModel.cs
index 37412e1..0bfd279 100644
--- a/Torch.Server/ViewModels/EntityTreeViewModel.cs
+++ b/Torch.Server/ViewModels/EntityTreeViewModel.cs
@@ -3,22 +3,28 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Windows.Controls;
using Sandbox.Game.Entities;
using Sandbox.Game.Entities.Character;
using Torch.Server.ViewModels.Entities;
using VRage.Game.ModAPI;
using VRage.ModAPI;
+using System.Windows.Threading;
+using NLog;
namespace Torch.Server.ViewModels
{
public class EntityTreeViewModel : ViewModel
{
- public MTObservableCollection Grids { get; set; } = new MTObservableCollection();
- public MTObservableCollection Characters { get; set; } = new MTObservableCollection();
- public MTObservableCollection FloatingObjects { get; set; } = new MTObservableCollection();
- public MTObservableCollection VoxelMaps { get; set; } = new MTObservableCollection();
+ //TODO: these should be sorted sets for speed
+ public ObservableList Grids { get; set; } = new ObservableList();
+ public ObservableList Characters { get; set; } = new ObservableList();
+ public ObservableList FloatingObjects { get; set; } = new ObservableList();
+ public ObservableList VoxelMaps { get; set; } = new ObservableList();
+ public Dispatcher ControlDispatcher => _control.Dispatcher;
private EntityViewModel _currentEntity;
+ private UserControl _control;
public EntityViewModel CurrentEntity
{
@@ -26,7 +32,12 @@ namespace Torch.Server.ViewModels
set { _currentEntity = value; OnPropertyChanged(); }
}
- public EntityTreeViewModel()
+ public EntityTreeViewModel(UserControl control)
+ {
+ _control = control;
+ }
+
+ public void Init()
{
MyEntities.OnEntityAdd += MyEntities_OnEntityAdd;
MyEntities.OnEntityRemove += MyEntities_OnEntityRemove;
@@ -56,20 +67,16 @@ namespace Torch.Server.ViewModels
switch (obj)
{
case MyCubeGrid grid:
- if (Grids.All(g => g.Entity.EntityId != obj.EntityId))
- Grids.Add(new GridViewModel(grid, this));
+ Grids.Insert(new GridViewModel(grid, this), g => g.Name);
break;
case MyCharacter character:
- if (Characters.All(g => g.Entity.EntityId != obj.EntityId))
- Characters.Add(new CharacterViewModel(character, this));
+ Characters.Insert(new CharacterViewModel(character, this), c => c.Name);
break;
case MyFloatingObject floating:
- if (FloatingObjects.All(g => g.Entity.EntityId != obj.EntityId))
- FloatingObjects.Add(new FloatingObjectViewModel(floating, this));
+ FloatingObjects.Insert(new FloatingObjectViewModel(floating, this), f => f.Name);
break;
case MyVoxelBase voxel:
- if (VoxelMaps.All(g => g.Entity.EntityId != obj.EntityId))
- VoxelMaps.Add(new VoxelMapViewModel(voxel, this));
+ VoxelMaps.Insert(new VoxelMapViewModel(voxel, this), v => v.Name);
break;
}
}
diff --git a/Torch.Server/ViewModels/PluginManagerViewModel.cs b/Torch.Server/ViewModels/PluginManagerViewModel.cs
index d6e7aa1..ed43547 100644
--- a/Torch.Server/ViewModels/PluginManagerViewModel.cs
+++ b/Torch.Server/ViewModels/PluginManagerViewModel.cs
@@ -11,7 +11,7 @@ namespace Torch.Server.ViewModels
{
public class PluginManagerViewModel : ViewModel
{
- public MTObservableCollection Plugins { get; } = new MTObservableCollection();
+ public ObservableList Plugins { get; } = new ObservableList();
private PluginViewModel _selectedPlugin;
public PluginViewModel SelectedPlugin
@@ -24,10 +24,12 @@ namespace Torch.Server.ViewModels
public PluginManagerViewModel(IPluginManager pluginManager)
{
+ foreach (var plugin in pluginManager)
+ Plugins.Add(new PluginViewModel(plugin));
pluginManager.PluginsLoaded += PluginManager_PluginsLoaded;
}
- private void PluginManager_PluginsLoaded(List obj)
+ private void PluginManager_PluginsLoaded(IList obj)
{
Plugins.Clear();
foreach (var plugin in obj)
diff --git a/Torch.Server/ViewModels/SessionSettingsViewModel.cs b/Torch.Server/ViewModels/SessionSettingsViewModel.cs
index 9dc583b..4dc3875 100644
--- a/Torch.Server/ViewModels/SessionSettingsViewModel.cs
+++ b/Torch.Server/ViewModels/SessionSettingsViewModel.cs
@@ -35,7 +35,7 @@ namespace Torch.Server.ViewModels
BlockLimits.Add(new BlockLimitViewModel(this, limit.Key, limit.Value));
}
- public MTObservableCollection BlockLimits { get; } = new MTObservableCollection();
+ public ObservableList BlockLimits { get; } = new ObservableList();
#region Multipliers
diff --git a/Torch.Server/Views/ChatControl.xaml b/Torch.Server/Views/ChatControl.xaml
index a9186c4..5e1b453 100644
--- a/Torch.Server/Views/ChatControl.xaml
+++ b/Torch.Server/Views/ChatControl.xaml
@@ -11,6 +11,7 @@
+
diff --git a/Torch.Server/Views/ChatControl.xaml.cs b/Torch.Server/Views/ChatControl.xaml.cs
index 52d4562..832f329 100644
--- a/Torch.Server/Views/ChatControl.xaml.cs
+++ b/Torch.Server/Views/ChatControl.xaml.cs
@@ -41,8 +41,10 @@ namespace Torch.Server
{
_server = (TorchBase)server;
_multiplayer = (MultiplayerManager)server.Multiplayer;
+ ChatItems.Items.Clear();
DataContext = _multiplayer;
- _multiplayer.ChatHistory.CollectionChanged += ChatHistory_CollectionChanged;
+ if (_multiplayer.ChatHistory is INotifyCollectionChanged ncc)
+ ncc.CollectionChanged += ChatHistory_CollectionChanged;
}
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@@ -74,22 +76,26 @@ namespace Torch.Server
return;
var commands = _server.Commands;
- string response = null;
if (commands.IsCommand(text))
{
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", text));
- _server.InvokeBlocking(() =>
+ _server.Invoke(() =>
{
- response = commands.HandleCommandFromServer(text);
+ var response = commands.HandleCommandFromServer(text);
+ Dispatcher.BeginInvoke(() => OnMessageEntered_Callback(response));
});
}
else
{
_server.Multiplayer.SendMessage(text);
}
+ Message.Text = "";
+ }
+
+ private void OnMessageEntered_Callback(string response)
+ {
if (!string.IsNullOrEmpty(response))
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", response));
- Message.Text = "";
}
}
}
diff --git a/Torch.Server/Views/ConfigControl.xaml b/Torch.Server/Views/ConfigControl.xaml
index f399687..2071c40 100644
--- a/Torch.Server/Views/ConfigControl.xaml
+++ b/Torch.Server/Views/ConfigControl.xaml
@@ -80,7 +80,7 @@
-
+
@@ -88,7 +88,7 @@
-
+
diff --git a/Torch.Server/Views/ConfigControl.xaml.cs b/Torch.Server/Views/ConfigControl.xaml.cs
index b931195..5614bb0 100644
--- a/Torch.Server/Views/ConfigControl.xaml.cs
+++ b/Torch.Server/Views/ConfigControl.xaml.cs
@@ -53,7 +53,6 @@ namespace Torch.Server.Views
Log.Info("Saved DS config.");
try
{
- //var checkpoint = MyLocalCache.LoadCheckpoint(Config.LoadWorld, out _);
MyObjectBuilderSerializer.DeserializeXML(Path.Combine(Config.LoadWorld, "Sandbox.sbc"), out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
if (checkpoint == null)
{
diff --git a/Torch.Server/Views/EntitiesControl.xaml b/Torch.Server/Views/EntitiesControl.xaml
index 2a78722..b4f0107 100644
--- a/Torch.Server/Views/EntitiesControl.xaml
+++ b/Torch.Server/Views/EntitiesControl.xaml
@@ -8,9 +8,6 @@
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
mc:Ignorable="d">
-
-
-
diff --git a/Torch.Server/Views/EntitiesControl.xaml.cs b/Torch.Server/Views/EntitiesControl.xaml.cs
index e29026a..0dc992a 100644
--- a/Torch.Server/Views/EntitiesControl.xaml.cs
+++ b/Torch.Server/Views/EntitiesControl.xaml.cs
@@ -27,12 +27,14 @@ namespace Torch.Server.Views
///
public partial class EntitiesControl : UserControl
{
- public EntityTreeViewModel Entities { get; set; } = new EntityTreeViewModel();
+ public EntityTreeViewModel Entities { get; set; }
public EntitiesControl()
{
InitializeComponent();
+ Entities = new EntityTreeViewModel(this);
DataContext = Entities;
+ Entities.Init();
}
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs