Merge pull request #205 from TorchAPI/GenericUI
Add ObjectCollectionEditor
This commit is contained in:
@@ -260,6 +260,9 @@
|
||||
<Compile Include="Views\DictionaryEditor.xaml.cs">
|
||||
<DependentUpon>DictionaryEditor.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\ObjectCollectionEditor.xaml.cs">
|
||||
<DependentUpon>ObjectCollectionEditor.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\PropertyGrid.xaml.cs">
|
||||
<DependentUpon>PropertyGrid.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -284,6 +287,10 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\ObjectCollectionEditor.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\PropertyGrid.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -21,11 +22,33 @@ namespace Torch.Views
|
||||
/// </summary>
|
||||
public partial class CollectionEditor : Window
|
||||
{
|
||||
private static readonly Dictionary<Type, MethodInfo> MethodCache = new Dictionary<Type, MethodInfo>();
|
||||
private static readonly MethodInfo EditMethod;
|
||||
|
||||
public CollectionEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
static CollectionEditor()
|
||||
{
|
||||
var m = typeof(CollectionEditor).GetMethods();
|
||||
EditMethod = m.First(mt => mt.Name == "Edit" && mt.GetGenericArguments().Length == 1);
|
||||
}
|
||||
|
||||
public void Edit(ICollection collection, string name)
|
||||
{
|
||||
var gt = collection.GetType().GenericTypeArguments[0];
|
||||
MethodInfo gm;
|
||||
if (!MethodCache.TryGetValue(gt, out gm))
|
||||
{
|
||||
gm = EditMethod.MakeGenericMethod(gt);
|
||||
MethodCache.Add(gt, gm);
|
||||
}
|
||||
|
||||
gm.Invoke(this, new object[] {collection, name});
|
||||
}
|
||||
|
||||
public void Edit<T>(ICollection<T> collection, string name)
|
||||
{
|
||||
ItemList.Text = string.Join("\r\n", collection.Select(x => x.ToString()));
|
||||
|
20
Torch/Views/ObjectCollectionEditor.xaml
Normal file
20
Torch/Views/ObjectCollectionEditor.xaml
Normal file
@@ -0,0 +1,20 @@
|
||||
<Window x:Class="Torch.Views.ObjectCollectionEditor"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Torch.Views"
|
||||
mc:Ignorable="d"
|
||||
Height="370" Width="410" Title="Edit Collection">
|
||||
<Grid>
|
||||
<local:PropertyGrid x:Name="PGrid" VerticalAlignment="Top" Height="300" Width="190" Margin="200,0,0,0"
|
||||
HorizontalAlignment="Right" />
|
||||
<ListBox x:Name="ElementList" Height="300" VerticalAlignment="Top" Width="190"
|
||||
HorizontalContentAlignment="Stretch" Margin="0,0,210,0" HorizontalAlignment="Left" />
|
||||
<Button x:Name="AddButton" Content="Add" HorizontalAlignment="Left" Margin="0,305,0,0" VerticalAlignment="Top"
|
||||
Width="90" />
|
||||
<Button x:Name="RemoveButton" Content="Remove" HorizontalAlignment="Left" Margin="100,305,0,0"
|
||||
VerticalAlignment="Top" Width="90" />
|
||||
|
||||
</Grid>
|
||||
</Window>
|
114
Torch/Views/ObjectCollectionEditor.xaml.cs
Normal file
114
Torch/Views/ObjectCollectionEditor.xaml.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
|
||||
namespace Torch.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ObjectCollectionEditor.xaml
|
||||
/// </summary>
|
||||
public partial class ObjectCollectionEditor : Window
|
||||
{
|
||||
private static readonly Dictionary<Type, MethodInfo> MethodCache = new Dictionary<Type, MethodInfo>();
|
||||
private static readonly MethodInfo EditMethod;
|
||||
|
||||
public ObjectCollectionEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
static ObjectCollectionEditor()
|
||||
{
|
||||
var m = typeof(ObjectCollectionEditor).GetMethods();
|
||||
EditMethod = m.First(mt => mt.Name == "Edit" && mt.GetGenericArguments().Length == 1);
|
||||
}
|
||||
|
||||
public void Edit(ICollection collection, string title)
|
||||
{
|
||||
if (collection == null)
|
||||
{
|
||||
MessageBox.Show("Cannot load null collection.", "Edit Error");
|
||||
return;
|
||||
}
|
||||
|
||||
var gt = collection.GetType().GenericTypeArguments[0];
|
||||
|
||||
//substitute for 'where T : new()'
|
||||
if (gt.GetConstructor(Type.EmptyTypes) == null)
|
||||
{
|
||||
MessageBox.Show("Unsupported collection type. Type must have paramaterless ctor.", "Edit Error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MethodCache.TryGetValue(gt, out MethodInfo gm))
|
||||
{
|
||||
gm = EditMethod.MakeGenericMethod(gt);
|
||||
MethodCache.Add(gt, gm);
|
||||
}
|
||||
|
||||
gm.Invoke(this, new object[] {collection, title});
|
||||
}
|
||||
|
||||
public void Edit<T>(ICollection<T> collection, string title) where T : new()
|
||||
{
|
||||
var oc = collection as ObservableCollection<T> ?? new ObservableCollection<T>(collection);
|
||||
|
||||
AddButton.Click += (sender, args) =>
|
||||
{
|
||||
var t = new T();
|
||||
oc.Add(t);
|
||||
ElementList.SelectedItem = t;
|
||||
};
|
||||
|
||||
RemoveButton.Click += RemoveButton_OnClick<T>;
|
||||
ElementList.SelectionChanged += ElementsList_OnSelected;
|
||||
|
||||
ElementList.ItemsSource = oc;
|
||||
|
||||
Title = title;
|
||||
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
ShowDialog();
|
||||
|
||||
if (!(collection is ObservableCollection<T>))
|
||||
{
|
||||
collection.Clear();
|
||||
foreach (var o in oc)
|
||||
collection.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveButton_OnClick<T>(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//this is kinda shitty, but item count is normally small, and it prevents CollectionModifiedExceptions
|
||||
var l = (ObservableCollection<T>)ElementList.ItemsSource;
|
||||
var r = new List<T>(ElementList.SelectedItems.Cast<T>());
|
||||
foreach (var item in r)
|
||||
l.Remove(item);
|
||||
if (l.Any())
|
||||
ElementList.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void ElementsList_OnSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = (sender as ListBox)?.SelectedItem;
|
||||
PGrid.DataContext = item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,6 +15,8 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
using VRage.Game;
|
||||
using VRage.Serialization;
|
||||
|
||||
@@ -124,6 +126,28 @@ namespace Torch.Views
|
||||
|
||||
valueControl = button;
|
||||
}
|
||||
else if (propertyType.IsGenericType && typeof(ICollection).IsAssignableFrom(propertyType.GetGenericTypeDefinition()))
|
||||
{
|
||||
var button = new Button
|
||||
{
|
||||
Content = "Edit Collection"
|
||||
};
|
||||
button.SetBinding(Button.DataContextProperty, $"{property.Name}");
|
||||
|
||||
var gt = propertyType.GetGenericArguments()[0];
|
||||
|
||||
//TODO: Is this the best option? Probably not
|
||||
if (gt.IsPrimitive || gt == typeof(string))
|
||||
{
|
||||
button.Click += (sender, args) => EditPrimitiveCollection(((Button)sender).DataContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
button.Click += (sender, args) => EditObjectCollection(((Button)sender).DataContext);
|
||||
}
|
||||
|
||||
valueControl = button;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueControl = new TextBox();
|
||||
@@ -149,6 +173,18 @@ namespace Torch.Views
|
||||
new DictionaryEditorDialog().Edit(dic);
|
||||
}
|
||||
|
||||
private void EditPrimitiveCollection(object collection, string title = "Collection Editor")
|
||||
{
|
||||
var c = (ICollection)collection;
|
||||
new CollectionEditor().Edit(c, title);
|
||||
}
|
||||
|
||||
private void EditObjectCollection(object collection, string title = "Collection Editor")
|
||||
{
|
||||
var c = (ICollection)collection;
|
||||
new ObjectCollectionEditor().Edit(c, title);
|
||||
}
|
||||
|
||||
private void UpdateFilter(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
var filterText = ((TextBox)sender).Text;
|
||||
|
Reference in New Issue
Block a user