Pārlūkot izejas kodu

Corrected Issues with Date values in grids
Improved Appearance of Direct Edit date/time fields

frogsoftware 1 gadu atpakaļ
vecāks
revīzija
ebc6403b75

+ 18 - 18
inabox.wpf/Behaviours/TextBox/TextBoxDateTimeMaskBehavior.cs

@@ -16,6 +16,8 @@ public class TextBoxDateTimeMaskBehavior : Behavior<TextBox>
 {
     private bool bFirst = true;
     private List<Tuple<int, char>> _separators = new List<Tuple<int, char>>();
+    private bool _isEnabled = true;
+    private bool _previouslyEnabled = true;
     
     private string _format = "";
     public string Format
@@ -27,6 +29,17 @@ public class TextBoxDateTimeMaskBehavior : Behavior<TextBox>
             ReloadSeparators();
         }
     }
+
+    public bool IsEnabled
+    {
+        get => _isEnabled;
+        set
+        {
+            _isEnabled = value;
+            if (AssociatedObject != null)
+                AssociatedObject.IsEnabled = value;
+        }
+    }
     
 
     private void ReloadSeparators()
@@ -45,11 +58,12 @@ public class TextBoxDateTimeMaskBehavior : Behavior<TextBox>
         }
     }
 
-    public TextBoxDateTimeMaskBehavior(string? format)
+    public TextBoxDateTimeMaskBehavior(string? format, bool isEnabled = true)
     {
         Format = String.IsNullOrWhiteSpace(format) 
             ? "dd/MM/yyyy HH:mm:ss" 
             : format;
+        _isEnabled = isEnabled;
     }
     
     protected override void OnAttached()
@@ -57,8 +71,8 @@ public class TextBoxDateTimeMaskBehavior : Behavior<TextBox>
         AssociatedObject.PreviewTextInput += PreviewTextInput;
         AssociatedObject.TextChanged += TextChanged;
         AssociatedObject.MouseDoubleClick += MouseDoubleClick;
-        //AssociatedObject.GotFocus -= GotFocus;
-        //AssociatedObject.PreviewKeyDown -= PreviewKeyDown;
+        _previouslyEnabled = AssociatedObject.IsEnabled;
+        AssociatedObject.IsEnabled = _isEnabled;
         base.OnAttached();
     }
     
@@ -67,24 +81,10 @@ public class TextBoxDateTimeMaskBehavior : Behavior<TextBox>
         AssociatedObject.MouseDoubleClick -= MouseDoubleClick;
         AssociatedObject.TextChanged -= TextChanged;
         AssociatedObject.PreviewTextInput -= PreviewTextInput;
-        //AssociatedObject.GotFocus += GotFocus;
-        //AssociatedObject.PreviewKeyDown += PreviewKeyDown; 
+        AssociatedObject.IsEnabled = _previouslyEnabled; 
         base.OnDetaching();
     }
     
-    
-    
-    // private void PreviewKeyDown(object sender, KeyEventArgs e)
-    // {
-    //     bFirst = false;
-    // }
-    //
-    //
-    // private void GotFocus(object sender, RoutedEventArgs e)
-    // {
-    //     //AssociatedObject.SelectAll();
-    // }
-
     private void MouseDoubleClick(object sender, MouseButtonEventArgs e)
     {
         AssociatedObject.Text = String.Format("{0:" + Format + "}", DateTime.Now);

+ 31 - 6
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDateColumn.cs

@@ -1,8 +1,13 @@
+using System;
+using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
+using Syncfusion.Windows.Controls.Grid;
 
 namespace InABox.DynamicGrid;
 
@@ -14,14 +19,34 @@ public class DynamicGridDateColumn<TEntity> : DynamicGridMaskColumn<TEntity,Date
 
     protected override IValueConverter CreateConverter() =>
         new DateToStringConverter(Definition?.Format);
+    
+    protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
+    {
+        if (value is DateTime datetime && buttons?.Any() == true)
+        {
+            foreach (var button in buttons)
+                button.Visibility = datetime.IsEmpty()
+                    ? Visibility.Collapsed
+                    : Visibility.Visible;
+        }
+    }
+
+    private readonly BitmapImage _clear = Wpf.Resources.delete.AsBitmapImage(20,20);
 
-    protected override Button[] CreateButtons(TextBox textbox)
+    protected override DynamicGridMaskColumnButton[]? CreateButtons()
     {
-        var button = new Button();
-        button.Content = "x";
-        button.Width = 25;
-        button.Click += (sender, args) => textbox.Text = "";
-        return new Button[] { button };
+        return new DynamicGridMaskColumnButton[]
+        {
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _clear,
+                Clicked = (sender,args) =>
+                {
+                    args.Value = DateTime.MinValue;
+                    sender.Visibility = Visibility.Collapsed;
+                }
+            }
+        };
     }
 
     public DynamicGridDateColumn(DynamicGridColumn definition) : base(definition)

+ 29 - 6
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDateTimeColumn.cs

@@ -1,8 +1,10 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
@@ -18,16 +20,37 @@ public class DynamicGridDateTimeColumn<TEntity> : DynamicGridMaskColumn<TEntity,
 
     protected override IValueConverter CreateConverter() =>
         new DateTimeToStringConverter(Definition?.Format);
+    
+    protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
+    {
+        if (value is DateTime datetime && buttons?.Any() == true)
+        {
+            foreach (var button in buttons)
+                button.Visibility = datetime.IsEmpty()
+                    ? Visibility.Collapsed
+                    : Visibility.Visible;
+        }
+    }
 
-    protected override Button[] CreateButtons(TextBox textbox)
+    private readonly BitmapImage _clear = Wpf.Resources.delete.AsBitmapImage(20,20);
+
+    protected override DynamicGridMaskColumnButton[]? CreateButtons()
     {
-        var button = new Button();
-        button.Content = "x";
-        button.Width = 25;
-        button.Click += (sender, args) => textbox.Text = "";
-        return new Button[] { button };
+        return new DynamicGridMaskColumnButton[]
+        {
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _clear,
+                Clicked = (sender,args) =>
+                {
+                    args.Value = DateTime.MinValue;
+                    sender.Visibility = Visibility.Collapsed;
+                }
+            }
+        };
     }
 
+
     public DynamicGridDateTimeColumn(DynamicGridColumn definition) : base(definition)
     {
     }

+ 34 - 26
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridDurationColumn.cs

@@ -2,6 +2,7 @@ using System;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
@@ -20,35 +21,42 @@ public class DynamicGridDurationColumn<TEntity> : DynamicGridMaskColumn<TEntity,
     protected override IValueConverter CreateConverter() =>
         new TimeSpanToStringConverter(Definition?.Format);
     
-    protected override Button[] CreateButtons(TextBox textbox)
+    private readonly BitmapImage _less = Wpf.Resources.downarrow.AsBitmapImage(20,20);
+    private readonly BitmapImage _more = Wpf.Resources.uparrow.AsBitmapImage(20,20);
+    
+    protected override DynamicGridMaskColumnButton[]? CreateButtons()
     {
-        var less = new Button();
-        less.Content = "-";
-        less.Width = 25;
-        less.Click += (sender, args) =>
+        return new DynamicGridMaskColumnButton[]
         {
-            var converter = new TimeSpanToStringConverter(Definition?.Format);
-            var time = converter.Deconvert(textbox.Text)
-                .Subtract(TimeSpan.FromMinutes(15));
-            if (time.Ticks < 0)
-                time = TimeSpan.Zero;
-            textbox.Text = converter.Convert(time);
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _less,
+                Clicked = (sender,args) =>
+                {
+                    if (args.Value is TimeSpan time)
+                    {
+                        time = time.Subtract(TimeSpan.FromMinutes(15));
+                        if (time.Ticks < 0)
+                            time = TimeSpan.Zero;
+                        args.Value = time;
+                    }
+                },
+                Position = DynamicGridMaskColumnButtonPosition.Left
+            },
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _more,
+                Clicked = (sender,args) =>
+                {
+                    if (args.Value is TimeSpan time)
+                    {
+                        time = time.Add(TimeSpan.FromMinutes(15));
+                        args.Value = time;
+                    }
+                },
+                Position = DynamicGridMaskColumnButtonPosition.Right
+            }
         };
-        
-        var more = new Button();
-        more.Content = "+";
-        more.Width = 25;
-        more.Click += (sender, args) =>
-        {
-            var converter = new TimeSpanToStringConverter(Definition?.Format);
-            var time = converter.Deconvert(textbox.Text)
-                .Subtract(TimeSpan.FromMinutes(15));
-            if (time.Ticks < 0)
-                time = TimeSpan.Zero;
-            textbox.Text = converter.Convert(time);
-        };
-        
-        return new Button[] { less, more };
     }
     
     public override GridSummaryColumn? Summary()

+ 156 - 44
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridMaskColumn.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Media;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
@@ -12,16 +14,47 @@ using Syncfusion.UI.Xaml.Grid;
 
 namespace InABox.DynamicGrid;
 
+public class DynamicGridMaskColumnButtonClickArgs
+{
+    public object? Value { get; set; }
+    public DynamicGridMaskColumnButtonClickArgs(object? value)
+    {
+        Value = value;
+    }
+}
+
+public enum DynamicGridMaskColumnButtonPosition
+{
+    Left,
+    Right
+}
+
+public class DynamicGridMaskColumnButton
+{
+    public BitmapImage? Image { get; set; }
+    
+    public Visibility Visibility { get; set; }
+
+    public DynamicGridMaskColumnButtonPosition Position { get; set; } = DynamicGridMaskColumnButtonPosition.Right;
+    
+    public Action<DynamicGridMaskColumnButton,DynamicGridMaskColumnButtonClickArgs>? Clicked { get; set; }
+
+    public object? DoClick(object? value)
+    {
+        var args = new DynamicGridMaskColumnButtonClickArgs(value);
+        Clicked?.Invoke(this, args);
+        return args.Value;
+    }
+}
+
 public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEditorColumn<TEntity, TEditor, GridTemplateColumn>
     where TEntity : BaseObject
     where TEditor : class,new() 
 {
 
-    protected abstract Behavior CreateBehaviour();
-
-    protected abstract IValueConverter CreateConverter();
+    protected abstract Behavior? CreateBehaviour();
 
-    protected abstract Button[] CreateButtons(TextBox textbox);
+    protected abstract IValueConverter? CreateConverter();
     
     protected override void Configure(GridTemplateColumn column, TEditor editor)
     {
@@ -30,12 +63,15 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
         (
             () =>
             {
-                var result = new Label();
-                result.HorizontalContentAlignment = Column.TextAlignment == TextAlignment.Left
-                    ? HorizontalAlignment.Left
-                    : Column.TextAlignment == TextAlignment.Center
-                        ? HorizontalAlignment.Center
-                        : HorizontalAlignment.Right;
+                var result = new Label
+                {
+                    HorizontalContentAlignment = Column.TextAlignment == TextAlignment.Left
+                        ? HorizontalAlignment.Left
+                        : Column.TextAlignment == TextAlignment.Center
+                            ? HorizontalAlignment.Center
+                            : HorizontalAlignment.Right,
+                    VerticalContentAlignment = VerticalAlignment.Center
+                };
                 var binding = new Binding()
                 {
                     Path = new PropertyPath(MappingName),
@@ -50,60 +86,136 @@ public abstract class DynamicGridMaskColumn<TEntity, TEditor> : DynamicGridEdito
         (
             () =>
             {
+                var border = new Border()
+                {
+                    BorderBrush = new SolidColorBrush(Colors.Gray),
+                    BorderThickness = new Thickness(0.75),
+                    Padding = new Thickness(0),
+                    Margin = new Thickness(0)
+                };
+                    
+                var dock = new DockPanel();
+                dock.SourceUpdated += OnSourceUpdated;
+                dock.TargetUpdated += OnTargetUpdated;
+                border.Child = dock;
                 
-                var result = new Grid();
-                result.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star)});
-                result.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto)});
+                var textbox = new TextBox
+                {
+                    CharacterCasing = CharacterCasing.Upper,
+                    TextAlignment = Column.TextAlignment,
+                    BorderThickness = new Thickness(0),
+                    //Padding = new Thickness(2, 0, 0, 0),
+                    VerticalContentAlignment = VerticalAlignment.Center,
+                    Background = new SolidColorBrush(Colors.White)
+                };
                 
-                var textbox = new TextBox();
-                textbox.CharacterCasing = CharacterCasing.Upper;
-                textbox.TextAlignment = Column.TextAlignment;
                 textbox.SetBinding(TextBox.TextProperty, new Binding()
                 {
                     Path = new PropertyPath(MappingName),
-                    Converter = converter
+                    Converter = converter,
+                    NotifyOnSourceUpdated = true,
+                    NotifyOnTargetUpdated = true,
+
                 });
                 
-                textbox.SetValue(Grid.ColumnSpanProperty, 2);
-                textbox.Padding = new Thickness(2, 0, 0, 0);
-                textbox.VerticalContentAlignment = VerticalAlignment.Center;
+                var behaviour = CreateBehaviour();
+                if (behaviour != null)
+                    Interaction.GetBehaviors(textbox).Add(behaviour);
+                
                 textbox.SetValue(FocusManagerHelper.FocusedElementProperty, true);
-
-                Interaction.GetBehaviors(textbox).Add(CreateBehaviour());
+                textbox.SetValue(DockPanel.DockProperty,Dock.Left);
                 
-                result.Children.Add(textbox);
-
-                var padding = 0.0;
-                var buttons = CreateButtons(textbox);
-                if (buttons?.Any() == true)
+                var defs = CreateButtons();
+                if (defs?.Any() == true)
                 {
-                    StackPanel stack = new StackPanel()
+                    foreach (var def in defs)
                     {
-                        Orientation = Orientation.Horizontal
-                    
-                    };
-                    stack.SetValue(Grid.ColumnProperty,1);
-                    result.Children.Add(stack);
-                    
-                    foreach (var button in buttons)
-                    {
-                        button.Margin = new Thickness(1);
-                        button.BorderThickness = new Thickness(0.75, 0, 0, 0);
-                        stack.Children.Add(button);
-                        padding += button.Width;
+                        Button button = new Button()
+                        {
+                            Tag = def,
+                            Content = new Image() { Source = def.Image },
+                            Padding = new Thickness(2),
+                            Width = 25,
+                            BorderThickness = new Thickness(0),
+                            Background = new SolidColorBrush(Colors.White),
+                            Visibility = def.Visibility,
+                        };
+                        button.Click += (sender, args) =>
+                        {
+                            var cvt = CreateConverter();
+                            var val = cvt != null
+                                ? cvt.ConvertBack(textbox.Text, typeof(object), null, CultureInfo.CurrentCulture)
+                                : textbox.Text;
+                            val = def.DoClick(val);
+                            textbox.Text = cvt != null
+                                ? cvt.Convert(val, typeof(String), null, CultureInfo.CurrentCulture) as String ?? ""
+                                : val?.ToString() ?? "";
+                            textbox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
+                            button.Content = new Image() { Source = def.Image };
+                            button.Visibility = def.Visibility;
+                        };
+                        button.SetValue(DockPanel.DockProperty,def.Position == DynamicGridMaskColumnButtonPosition.Left ? Dock.Left : Dock.Right);
+                        dock.Children.Add(button);
                     }
-                    
                 }
-
-                textbox.Padding = new Thickness(0, 0, padding, 0);
                 
-                return result;
+                dock.Children.Add(textbox);
+                
+                return border;
             }
             
         );
         column.SetCellBoundValue = false;
     }
 
+    protected virtual DynamicGridMaskColumnButton[]? CreateButtons()
+    {
+        return null;
+    }
+    
+    private void OnTargetUpdated(object? sender, DataTransferEventArgs e)
+    {
+        if (sender is DockPanel dock && e.Source is TextBox textbox && e.Property == TextBox.TextProperty)
+        {
+            var buttons = dock?.Children.OfType<Button>().ToArray();
+            var defs = buttons?.Select(x => x.Tag).OfType<DynamicGridMaskColumnButton>()?.ToArray();
+            if (defs?.Any() == true)
+            {
+                var cvt = CreateConverter();
+                var val = cvt != null
+                    ? cvt.ConvertBack(textbox.Text, typeof(object), null, CultureInfo.CurrentCulture)
+                    : textbox.Text;
+                UpdateButtons(val, defs);
+                if (buttons != null)
+                    foreach (var button in buttons)
+                    {
+                        var def = button.Tag as DynamicGridMaskColumnButton;
+                        button.Content = new Image() { Source = def?.Image };
+                        button.Visibility = def?.Visibility ?? Visibility.Collapsed;
+                    }
+            }
+        }
+    }
+    
+    protected virtual void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
+    {
+        
+    }
+
+    private void OnSourceUpdated(object? sender, DataTransferEventArgs e)
+    {
+        if (sender is DockPanel dock && e.Source is TextBox textbox && e.Property == TextBox.TextProperty)
+        {
+            var buttons = dock?.Children.OfType<Button>().ToArray();
+            SourceUpdated(textbox.Text, buttons ?? new Button[] { });
+        }
+    }
+
+    protected virtual void SourceUpdated(string text, Button[] buttons)
+    {
+        
+    }
+
     protected DynamicGridMaskColumn(DynamicGridColumn definition) : base(definition)
     {
     }

+ 29 - 6
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridTimeOfDayColumn.cs

@@ -1,7 +1,10 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
@@ -16,13 +19,33 @@ public class DynamicGridTimeOfDayColumn<TEntity> : DynamicGridMaskColumn<TEntity
     protected override IValueConverter CreateConverter() =>
         new TimeSpanToStringConverter(Definition?.Format);
     
-    protected override Button[] CreateButtons(TextBox textbox)
+    protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
     {
-        var button = new Button();
-        button.Content = "x";
-        button.Width = 25;
-        button.Click += (sender, args) => textbox.Text = "";
-        return new Button[] { button };
+        if (value is TimeSpan timespan && buttons?.Any() == true)
+        {
+            foreach (var button in buttons)
+                button.Visibility = timespan == TimeSpan.Zero
+                    ? Visibility.Collapsed
+                    : Visibility.Visible;
+        }
+    }
+
+    private readonly BitmapImage _clear = Wpf.Resources.delete.AsBitmapImage(20,20);
+
+    protected override DynamicGridMaskColumnButton[]? CreateButtons()
+    {
+        return new DynamicGridMaskColumnButton[]
+        {
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _clear,
+                Clicked = (sender,args) =>
+                {
+                    args.Value = TimeSpan.Zero;
+                    sender.Visibility = Visibility.Collapsed;
+                }
+            }
+        };
     }
 
     public DynamicGridTimeOfDayColumn(DynamicGridColumn definition) : base(definition)

+ 41 - 9
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridTimeStampColumn.cs

@@ -1,30 +1,62 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Controls;
 using System.Windows.Data;
+using System.Windows.Media.Imaging;
 using InABox.Core;
 using InABox.WPF;
 using Microsoft.Xaml.Behaviors;
 
 namespace InABox.DynamicGrid;
 
-public class DynamicGridTimeStampColumn<TEntity> : DynamicGridMaskColumn<TEntity,DateTimeEditor> where TEntity : BaseObject
+public class DynamicGridTimeStampColumn<TEntity> : DynamicGridMaskColumn<TEntity,TimestampEditor> where TEntity : BaseObject
 {
     protected override Behavior CreateBehaviour() => 
-        new TextBoxDateTimeMaskBehavior(Definition?.Format);
+        new TextBoxDateTimeMaskBehavior(Definition?.Format, false);
 
     protected override IValueConverter CreateConverter() =>
         new DateTimeToStringConverter(Definition?.Format);
-
-    protected override Button[] CreateButtons(TextBox textbox)
+    
+    protected override void UpdateButtons(object? value, DynamicGridMaskColumnButton[]? buttons)
     {
-        var button = new Button();
-        button.Content = "x";
-        button.Width = 25;
-        button.Click += (sender, args) => textbox.Text = "";
-        return new Button[] { button };
+        if (value is DateTime datetime && buttons?.Any() == true)
+        {
+            foreach (var button in buttons)
+                button.Image = datetime.IsEmpty()
+                    ? _set
+                    : _clear;
+        }
     }
+    
+    private readonly BitmapImage _clear = Wpf.Resources.delete.AsBitmapImage(20,20);
+    private readonly BitmapImage _set = Wpf.Resources.tick.AsBitmapImage(20,20);
+    
+    protected override DynamicGridMaskColumnButton[]? CreateButtons()
+    {
+        return new DynamicGridMaskColumnButton[]
+        {
+            new DynamicGridMaskColumnButton()
+            {
+                Image = _set,
+                Clicked = (sender,args) =>
+                {
+                    if (args.Value is DateTime datetime)
+                    {
+                        datetime = datetime.IsEmpty()
+                            ? DateTime.Now
+                            : DateTime.MinValue;
+                        args.Value = datetime;
+                        sender.Image = datetime.IsEmpty()
+                            ? _set
+                            : _clear;
 
+                    }
+                }
+            }
+        };
+    }
+    
     public DynamicGridTimeStampColumn(DynamicGridColumn definition) : base(definition)
     {
     }

+ 69 - 0
inabox.wpf/DynamicGrid/Columns/EditorColumns/DynamicGridUniqueCodeColumn.cs

@@ -0,0 +1,69 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using InABox.Core;
+using InABox.WPF;
+using Syncfusion.UI.Xaml.Grid;
+
+namespace InABox.DynamicGrid;
+
+public class DynamicGridUniqueCodeColumn<TEntity> : DynamicGridEditorColumn<TEntity,UniqueCodeEditor,GridTemplateColumn> where TEntity : BaseObject
+{
+
+    protected override void Configure(GridTemplateColumn column, UniqueCodeEditor editor)
+    {
+        column.CellTemplate = TemplateGenerator.CreateDataTemplate
+        (
+            () =>
+            {
+                var result = new Label();
+                result.HorizontalContentAlignment = Column.TextAlignment == TextAlignment.Left
+                    ? HorizontalAlignment.Left
+                    : Column.TextAlignment == TextAlignment.Center
+                        ? HorizontalAlignment.Center
+                        : HorizontalAlignment.Right;
+                var binding = new Binding()
+                {
+                    Path = new PropertyPath(MappingName),
+                };
+                result.SetBinding(Label.ContentProperty, binding);
+                return result;
+            }
+        );
+
+        column.EditTemplate = TemplateGenerator.CreateDataTemplate
+        (
+            () =>
+            {
+                var textbox = new TextBox();
+                textbox.CharacterCasing = CharacterCasing.Upper;
+                textbox.TextAlignment = Column.TextAlignment;
+                textbox.SetBinding(TextBox.TextProperty, new Binding()
+                {
+                    Path = new PropertyPath(MappingName)
+                });
+                
+                textbox.SetValue(Grid.ColumnSpanProperty, 2);
+                textbox.Padding = new Thickness(2, 0, 0, 0);
+                textbox.VerticalContentAlignment = VerticalAlignment.Center;
+                textbox.PreviewTextInput += (sender, args) => textbox.Tag = true;
+                textbox.TextChanged += (sender, args) =>
+                {
+                    if (Equals(textbox.Tag, false))
+                    {
+                        textbox.SelectAll();
+                        textbox.Tag = true;
+                    }
+                };
+                textbox.SetValue(FocusManagerHelper.FocusedElementProperty, true);
+                
+                return textbox;
+            }
+        );
+
+    }
+    
+    public DynamicGridUniqueCodeColumn(DynamicGridColumn definition) : base(definition)
+    {
+    }
+}

+ 36 - 35
inabox.wpf/DynamicGrid/DynamicGrid.cs

@@ -1500,49 +1500,48 @@ namespace InABox.DynamicGrid
             if (Data == null || width <= 0)
                 return;
 
-            var fAvailWidth = width;
+            Dispatcher.BeginInvoke(() =>
+            {
+                var fAvailWidth = width;
 
-            //if (Data.Rows.Count * (DataGrid.RowHeight + 1) + DataGrid.HeaderRowHeight > height + 0.5F)
-            if (height < DataGrid.AutoScroller.VScrollBar.Maximum)
-                fAvailWidth -= (SystemParameters.VerticalScrollBarWidth + 0.75);
+                //if (Data.Rows.Count * (DataGrid.RowHeight + 1) + DataGrid.HeaderRowHeight > height + 0.5F)
+                if (height < DataGrid.AutoScroller.VScrollBar.Maximum)
+                    fAvailWidth -= (SystemParameters.VerticalScrollBarWidth + 0.75);
 
 
-            double fCurWidth = 0.0F;
-            var NumAutoCols = 0;
+                double fCurWidth = 0.0F;
+                var NumAutoCols = 0;
 
 
-            var colWidths = new Dictionary<int, double>();
-            for (var i = 0; i < ColumnList.Count; i++)
-            {
-                var col = ColumnList[i];
-                if (col is DynamicActionColumn dac)
+                var colWidths = new Dictionary<int, double>();
+                for (var i = 0; i < ColumnList.Count; i++)
                 {
-                    colWidths[i] = dac.Width == 0 ? RowHeight : dac.Width;
-                    fCurWidth += colWidths[i];
+                    var col = ColumnList[i];
+                    if (col is DynamicActionColumn dac)
+                    {
+                        colWidths[i] = dac.Width == 0 ? RowHeight : dac.Width;
+                        fCurWidth += colWidths[i];
+                    }
+                    else if (col is DynamicGridColumn dgc)
+                    {
+                        colWidths[i] = dgc.Width;
+                        if (dgc.Width != 0)
+                            fCurWidth += Math.Max(0.0F, dgc.Width);
+                        else
+                            NumAutoCols++;
+                    }
                 }
-                else if (col is DynamicGridColumn dgc)
+
+                if (NumAutoCols > 0)
                 {
-                    colWidths[i] = dgc.Width;
-                    if (dgc.Width != 0)
-                        fCurWidth += Math.Max(0.0F, dgc.Width);
-                    else
-                        NumAutoCols++;
+                    var fAutoWidth = (fAvailWidth - fCurWidth) / NumAutoCols;
+                    if (fAutoWidth < 100)
+                        fAutoWidth = 100;
+                    for (var i = 0; i < ColumnList.Count; i++)
+                        if (colWidths[i] == 0)
+                            colWidths[i] = fAutoWidth;
                 }
-            }
-
-            if (NumAutoCols > 0)
-            {
-                var fAutoWidth = (fAvailWidth - fCurWidth) / NumAutoCols;
-                if (fAutoWidth < 100)
-                    fAutoWidth = 100;
-                for (var i = 0; i < ColumnList.Count; i++)
-                    if (colWidths[i] == 0)
-                        colWidths[i] = fAutoWidth;
-            }
-
-
-            Dispatcher.BeginInvoke(() =>
-            {
+                
                 foreach (var index in colWidths.Keys)
                     DataGrid.Columns[index].Width = Math.Max(0.0F, colWidths[index]);
             });
@@ -1760,7 +1759,9 @@ namespace InABox.DynamicGrid
                     else if (prop.Editor is MemoEditor)
                         newcol = new DynamicGridMemoColumn<T>(column);
                     else if (prop.Editor is CodeEditor)
-                        newcol = new DynamicGridCodeColumn<T>(column);
+                        newcol = new DynamicGridCodeColumn<T>(column);                    
+                    else if (prop.Editor is UniqueCodeEditor)
+                        newcol = new DynamicGridUniqueCodeColumn<T>(column);
                     else if (prop.Editor is TextBoxEditor)
                         newcol = new DynamicGridTextBoxColumn<T>(column);