Procházet zdrojové kódy

Added some binding utility methods

Kenric Nugteren před 11 měsíci
rodič
revize
d5e042ba10

+ 255 - 258
inabox.wpf/DynamicGrid/DynamicGridStyle.cs

@@ -5,349 +5,346 @@ using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Media;
-using com.sun.xml.@internal.ws.api.streaming;
 using InABox.Clients;
 using InABox.Core;
 using InABox.Scripting;
 using Syncfusion.UI.Xaml.Grid;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+public delegate DynamicGridStyle OnGetDynamicGridRowStyle(CoreRow row, DynamicGridStyle defaultstyle);
+
+public interface IBaseDynamicGridStyle
 {
-    public delegate DynamicGridStyle OnGetDynamicGridRowStyle(CoreRow row, DynamicGridStyle defaultstyle);
-    
-    public interface IBaseDynamicGridStyle
+    double FontSize { get; set; }
+    FontStyle FontStyle { get; set; }
+    FontWeight FontWeight { get; set; }
+    Brush Background { get; set; }
+    Brush Foreground { get; set; }
+}
+
+public interface IDynamicGridStyle : IBaseDynamicGridStyle
+{
+    DependencyProperty FontSizeProperty { get; }
+    DependencyProperty FontStyleProperty { get; }
+    DependencyProperty FontWeightProperty { get; }
+    DependencyProperty BackgroundProperty { get; }
+    DependencyProperty ForegroundProperty { get; }
+}
+
+public abstract class DynamicGridStyle : Style, IDynamicGridStyle
+{
+    public DynamicGridStyle(Type T) : base(T)
     {
-        double FontSize { get; set; }
-        FontStyle FontStyle { get; set; }
-        FontWeight FontWeight { get; set; }
-        Brush Background { get; set; }
-        Brush Foreground { get; set; }
+        FontSize = 12D;
+        FontWeight = FontWeights.Normal;
+        FontStyle = FontStyles.Normal;
+        Background = new SolidColorBrush(Colors.White);
+        Foreground = new SolidColorBrush(Colors.Black);
     }
 
-    public interface IDynamicGridStyle : IBaseDynamicGridStyle
+    public DynamicGridStyle(DynamicGridStyle source) : base(source.TargetType, source)
     {
-        DependencyProperty FontSizeProperty { get; }
-        DependencyProperty FontStyleProperty { get; }
-        DependencyProperty FontWeightProperty { get; }
-        DependencyProperty BackgroundProperty { get; }
-        DependencyProperty ForegroundProperty { get; }
+        FontSize = source.FontSize;
+        FontWeight = source.FontWeight;
+        FontStyle = source.FontStyle;
+        Background = source.Background;
+        Foreground = source.Foreground;
     }
 
-    public abstract class DynamicGridStyle : Style, IDynamicGridStyle
-    {
-        public DynamicGridStyle(Type T) : base(T)
-        {
-            FontSize = 12D;
-            FontWeight = FontWeights.Normal;
-            FontStyle = FontStyles.Normal;
-            Background = new SolidColorBrush(Colors.White);
-            Foreground = new SolidColorBrush(Colors.Black);
-        }
+    public abstract DependencyProperty FontSizeProperty { get; }
 
-        public DynamicGridStyle(DynamicGridStyle source) : base(source.TargetType, source)
-        {
-            FontSize = source.FontSize;
-            FontWeight = source.FontWeight;
-            FontStyle = source.FontStyle;
-            Background = source.Background;
-            Foreground = source.Foreground;
-        }
+    public abstract DependencyProperty FontStyleProperty { get; }
 
-        public abstract DependencyProperty FontSizeProperty { get; }
+    public abstract DependencyProperty FontWeightProperty { get; }
 
-        public abstract DependencyProperty FontStyleProperty { get; }
+    public abstract DependencyProperty BackgroundProperty { get; }
 
-        public abstract DependencyProperty FontWeightProperty { get; }
+    public abstract DependencyProperty ForegroundProperty { get; }
 
-        public abstract DependencyProperty BackgroundProperty { get; }
-
-        public abstract DependencyProperty ForegroundProperty { get; }
+    public double FontSize
+    {
+        get => Get<double>(FontSizeProperty, 8);
+        set => Set(FontSizeProperty, value);
+    }
 
-        public double FontSize
-        {
-            get => Get<double>(FontSizeProperty, 8);
-            set => Set(FontSizeProperty, value);
-        }
+    public FontStyle FontStyle
+    {
+        get => Get(FontStyleProperty, FontStyles.Italic);
+        set => Set(FontStyleProperty, value);
+    }
 
-        public FontStyle FontStyle
-        {
-            get => Get(FontStyleProperty, FontStyles.Italic);
-            set => Set(FontStyleProperty, value);
-        }
+    public FontWeight FontWeight
+    {
+        get => Get(FontWeightProperty, FontWeights.DemiBold);
+        set => Set(FontWeightProperty, value);
+    }
 
-        public FontWeight FontWeight
-        {
-            get => Get(FontWeightProperty, FontWeights.DemiBold);
-            set => Set(FontWeightProperty, value);
-        }
+    public Brush Background
+    {
+        get => Get<Brush>(BackgroundProperty, new SolidColorBrush(Colors.Yellow));
+        set => Set(BackgroundProperty, value);
+    }
 
-        public Brush Background
-        {
-            get => Get<Brush>(BackgroundProperty, new SolidColorBrush(Colors.Yellow));
-            set => Set(BackgroundProperty, value);
-        }
 
+    public Brush Foreground
+    {
+        get => Get<Brush>(ForegroundProperty, new SolidColorBrush(Colors.Green));
+        set => Set(ForegroundProperty, value);
+    }
 
-        public Brush Foreground
+    private void Set<T>(DependencyProperty property, T value)
+    {
+        var setter = Setters.FirstOrDefault(x => x is Setter && ((Setter)x).Property.Equals(property)) as Setter;
+        if (setter == null)
         {
-            get => Get<Brush>(ForegroundProperty, new SolidColorBrush(Colors.Green));
-            set => Set(ForegroundProperty, value);
+            Setters.Add(new Setter(property, value));
         }
-
-        private void Set<T>(DependencyProperty property, T value)
+        else
         {
-            var setter = Setters.FirstOrDefault(x => x is Setter && ((Setter)x).Property.Equals(property)) as Setter;
-            if (setter == null)
-            {
-                Setters.Add(new Setter(property, value));
-            }
-            else
-            {
-                if (!setter.IsSealed)
-                    setter.Value = value;
-            }
+            if (!setter.IsSealed)
+                setter.Value = value;
         }
+    }
 
-        private T Get<T>(DependencyProperty property, T defaultvalue)
-        {
-            var setter = Setters.FirstOrDefault(x => x is Setter && ((Setter)x).Property.Equals(property)) as Setter;
-            return setter != null ? (T)setter.Value : defaultvalue;
-        }
+    private T Get<T>(DependencyProperty property, T defaultvalue)
+    {
+        var setter = Setters.FirstOrDefault(x => x is Setter && ((Setter)x).Property.Equals(property)) as Setter;
+        return setter != null ? (T)setter.Value : defaultvalue;
     }
+}
 
-    public abstract class DynamicGridStyle<T> : DynamicGridStyle
+public abstract class DynamicGridStyle<T> : DynamicGridStyle
+{
+    public DynamicGridStyle(IDynamicGridStyle? source) : base(typeof(T))
     {
-        public DynamicGridStyle(IDynamicGridStyle? source) : base(typeof(T))
+        if (source != null)
         {
-            if (source != null)
-            {
-                FontSize = source.FontSize;
-                FontStyle = source.FontStyle;
-                FontWeight = source.FontWeight;
-                Background = source.Background;
-                Foreground = source.Foreground;
-            }
+            FontSize = source.FontSize;
+            FontStyle = source.FontStyle;
+            FontWeight = source.FontWeight;
+            Background = source.Background;
+            Foreground = source.Foreground;
         }
     }
+}
 
-    public abstract class DynamicGridRowStyleSelector<T> : StyleSelector, IBaseDynamicGridStyle
-    {
-        private static bool initialized;
+public abstract class DynamicGridRowStyleSelector<T> : StyleSelector, IBaseDynamicGridStyle
+{
+    private static bool initialized;
 
-        private static ScriptDocument? helper;
+    private static ScriptDocument? helper;
 
-        private static DynamicGridStyle defaultstyle;
+    private static DynamicGridStyle defaultstyle;
 
-        public CoreTable Data { get; set; }
-        
-        public double FontSize
-        {
-            get => defaultstyle.FontSize;
-            set => defaultstyle.FontSize = value;
-        }
+    public CoreTable Data { get; set; }
+    
+    public double FontSize
+    {
+        get => defaultstyle.FontSize;
+        set => defaultstyle.FontSize = value;
+    }
 
-        public FontStyle FontStyle
-        {
-            get => defaultstyle.FontStyle;
-            set => defaultstyle.FontStyle = value;
-        }
+    public FontStyle FontStyle
+    {
+        get => defaultstyle.FontStyle;
+        set => defaultstyle.FontStyle = value;
+    }
 
-        public FontWeight FontWeight
-        {
-            get => defaultstyle.FontWeight;
-            set => defaultstyle.FontWeight = value;
-        }
+    public FontWeight FontWeight
+    {
+        get => defaultstyle.FontWeight;
+        set => defaultstyle.FontWeight = value;
+    }
 
-        public Brush Background
-        {
-            get => defaultstyle.Background;
-            set => defaultstyle.Background = value;
-        }
+    public Brush Background
+    {
+        get => defaultstyle.Background;
+        set => defaultstyle.Background = value;
+    }
 
-        public Brush Foreground
-        {
-            get => defaultstyle.Foreground;
-            set => defaultstyle.Foreground = value;
-        }
+    public Brush Foreground
+    {
+        get => defaultstyle.Foreground;
+        set => defaultstyle.Foreground = value;
+    }
 
-        protected abstract DynamicGridStyle CreateStyle();
+    protected abstract DynamicGridStyle CreateStyle();
 
-        private CoreRow? GetRow(object item)
+    private CoreRow? GetRow(object item)
+    {
+        try
         {
-            try
+            var row = (item as DataRowBase)?.RowData as DataRowView;
+            if (row != null)
             {
-                var row = (item as DataRowBase)?.RowData as DataRowView;
-                if (row != null)
-                {
-                    var index = row.Row.Table.Rows.IndexOf(row.Row);
-                    return Data.Rows[index];
-                }
-
-                return null;
+                var index = row.Row.Table.Rows.IndexOf(row.Row);
+                return Data.Rows[index];
             }
-            catch
-            {
-                return null;
-            }
-        }
-
 
-        private void Initialize()
+            return null;
+        }
+        catch
         {
-            if (initialized)
-                return;
+            return null;
+        }
+    }
 
-            defaultstyle = CreateStyle();
 
-            var stylescript = ClientFactory.ClientType == null
-                ? null
-                : new Client<Script>()
-                    .Load(new Filter<Script>(x => x.Section).IsEqualTo(typeof(T).EntityName()).And(x => x.ScriptType).IsEqualTo(ScriptType.RowStyle))
-                    .FirstOrDefault();
-            if (stylescript != null)
-            {
-                helper = new ScriptDocument(stylescript.Code);
-                if (!helper.Compile())
-                    helper = null;
-            }
+    private void Initialize()
+    {
+        if (initialized)
+            return;
+
+        defaultstyle = CreateStyle();
 
-            initialized = true;
+        var stylescript = ClientFactory.ClientType == null
+            ? null
+            : new Client<Script>()
+                .Load(new Filter<Script>(x => x.Section).IsEqualTo(typeof(T).EntityName()).And(x => x.ScriptType).IsEqualTo(ScriptType.RowStyle))
+                .FirstOrDefault();
+        if (stylescript != null)
+        {
+            helper = new ScriptDocument(stylescript.Code);
+            if (!helper.Compile())
+                helper = null;
         }
 
-        public event OnGetDynamicGridRowStyle? GetStyle;
+        initialized = true;
+    }
 
-        private DynamicGridStyle ExecuteHelper(CoreRow row, DynamicGridStyle style)
-        {
-            var result = style;
+    public event OnGetDynamicGridRowStyle? GetStyle;
+
+    private DynamicGridStyle ExecuteHelper(CoreRow row, DynamicGridStyle style)
+    {
+        var result = style;
 
-            try
+        try
+        {
+            if(helper is null)
             {
-                if(helper is null)
-                {
-                    throw new Exception("Helper is null");
-                }
-                helper.SetValue("Row", row);
-                helper.SetValue("Background", style.Background);
-                helper.SetValue("Foreground", style.Foreground);
-                helper.SetValue("Style", style.FontStyle);
-                helper.SetValue("Weight", style.FontWeight);
-                helper.SetValue("Size", style.FontSize);
-
-                if (helper.Execute())
-                {
-                    result = CreateStyle();
-                    result.Background = (Brush)helper.GetValue("Background");
-                    result.Foreground = (Brush)helper.GetValue("Foreground");
-                    result.FontStyle = (FontStyle)helper.GetValue("Style");
-                    result.FontWeight = (FontWeight)helper.GetValue("Weight");
-                    result.FontSize = (double)helper.GetValue("Size");
-                }
+                throw new Exception("Helper is null");
             }
-            catch (Exception e)
+            helper.SetValue("Row", row);
+            helper.SetValue("Background", style.Background);
+            helper.SetValue("Foreground", style.Foreground);
+            helper.SetValue("Style", style.FontStyle);
+            helper.SetValue("Weight", style.FontWeight);
+            helper.SetValue("Size", style.FontSize);
+
+            if (helper.Execute())
             {
-                Logger.Send(LogType.Information, "", "Unable to Invoke Row Style Helper: " + e.Message);
+                result = CreateStyle();
+                result.Background = (Brush)helper.GetValue("Background");
+                result.Foreground = (Brush)helper.GetValue("Foreground");
+                result.FontStyle = (FontStyle)helper.GetValue("Style");
+                result.FontWeight = (FontWeight)helper.GetValue("Weight");
+                result.FontSize = (double)helper.GetValue("Size");
             }
-
-            return result;
         }
-
-        public override Style SelectStyle(object item, DependencyObject container)
+        catch (Exception e)
         {
-            Initialize();
+            Logger.Send(LogType.Information, "", "Unable to Invoke Row Style Helper: " + e.Message);
+        }
+
+        return result;
+    }
+
+    public override Style SelectStyle(object item, DependencyObject container)
+    {
+        Initialize();
 
-            if (Data == null)
-                return defaultstyle;
+        if (Data == null)
+            return defaultstyle;
 
-            if (item == null)
-                return defaultstyle;
+        if (item == null)
+            return defaultstyle;
 
-            var row = GetRow(item);
+        var row = GetRow(item);
 
-            if (row == null)
-                return defaultstyle;
+        if (row == null)
+            return defaultstyle;
 
-            var style = GetStyle != null ? GetStyle(row, defaultstyle) : defaultstyle;
+        var style = GetStyle != null ? GetStyle(row, defaultstyle) : defaultstyle;
 
-            if (helper != null)
-                return ExecuteHelper(row, style);
+        if (helper != null)
+            return ExecuteHelper(row, style);
 
-            return style;
-        }
+        return style;
     }
+}
 
-    public class DynamicGridRowStyleSelector<TEntity, TStyle> : DynamicGridRowStyleSelector<TEntity> where TStyle : DynamicGridStyle, new()
+public class DynamicGridRowStyleSelector<TEntity, TStyle> : DynamicGridRowStyleSelector<TEntity> where TStyle : DynamicGridStyle, new()
+{
+    protected override DynamicGridStyle CreateStyle()
     {
-        protected override DynamicGridStyle CreateStyle()
-        {
-            return new TStyle();
-        }
+        return new TStyle();
     }
+}
 
-    public class DynamicGridCellStyleParameters
-    {
-        public DynamicColumnBase Column { get; }
-        
-        public object DefaultValue { get; }
+public class DynamicGridCellStyleParameters
+{
+    public DynamicColumnBase Column { get; }
+    
+    public object DefaultValue { get; }
 
-        public DynamicGridCellStyleParameters(DynamicColumnBase column, object? defaultValue)
-        {
-            Column = column;
-            DefaultValue = defaultValue;
-        }
+    public DynamicGridCellStyleParameters(DynamicColumnBase column, object? defaultValue)
+    {
+        Column = column;
+        DefaultValue = defaultValue;
     }
+}
 
-    public class DynamicGridCellStyleConverter<T> : IValueConverter
-    {
+public class DynamicGridCellStyleConverter<T> : IValueConverter
+{
 
-        private readonly IDynamicGrid _grid;
-        
-        private readonly Func<CoreRow, DynamicColumnBase, T> _converter;
-        
-        public DynamicGridCellStyleConverter(IDynamicGrid grid, Func<CoreRow, DynamicColumnBase, T> converter)
-        {
-            _grid = grid ?? throw new ArgumentNullException(nameof(grid));
-            _converter = converter ?? throw new ArgumentNullException(nameof(converter));
-        }
+    private readonly IDynamicGrid _grid;
+    
+    private readonly Func<CoreRow, DynamicColumnBase, T> _converter;
+    
+    public DynamicGridCellStyleConverter(IDynamicGrid grid, Func<CoreRow, DynamicColumnBase, T> converter)
+    {
+        _grid = grid ?? throw new ArgumentNullException(nameof(grid));
+        _converter = converter ?? throw new ArgumentNullException(nameof(converter));
+    }
 
-        private CoreRow? GetRow(object item)
+    private CoreRow? GetRow(object item)
+    {
+        try
         {
-            try
+            var row = item as DataRowView;
+            if (row != null)
             {
-                var row = item as DataRowView;
-                if (row != null)
-                {
-                    var index = row.Row.Table.Rows.IndexOf(row.Row);
-                    return _grid.Data.Rows[index];
-                }
-                return null;
-            }
-            catch
-            {
-                return null;
+                var index = row.Row.Table.Rows.IndexOf(row.Row);
+                return _grid.Data.Rows[index];
             }
+            return null;
         }
-        
-        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        catch
         {
-            var row = GetRow(value);
-            if (row == null)
-                return DependencyProperty.UnsetValue;
-
-            var param = parameter as DynamicGridCellStyleParameters;
-            if (param == null)
-                return DependencyProperty.UnsetValue;
-            
-            //var column = parameter as DynamicColumnBase;
-            //if (column is null)
-            //    return DependencyProperty.UnsetValue;
-            
-            return _converter.Invoke(row,param.Column) ?? param.DefaultValue;
+            return null;
         }
+    }
+    
+    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+        var row = GetRow(value);
+        if (row == null)
+            return DependencyProperty.UnsetValue;
+
+        var param = parameter as DynamicGridCellStyleParameters;
+        if (param == null)
+            return DependencyProperty.UnsetValue;
         
-        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
-        {
-            throw new NotSupportedException();
-        }
+        //var column = parameter as DynamicColumnBase;
+        //if (column is null)
+        //    return DependencyProperty.UnsetValue;
+        
+        return _converter.Invoke(row,param.Column) ?? param.DefaultValue;
     }
     
-}
+    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+        throw new NotSupportedException();
+    }
+}

+ 53 - 51
inabox.wpf/DynamicGrid/DynamicItemsListGrid.cs

@@ -8,72 +8,74 @@ using System.Threading.Tasks;
 using Microsoft.CodeAnalysis.CSharp.Syntax;
 using Syncfusion.Windows.Tools.Controls;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+
+public interface IDynamicItemsListGrid : IDynamicGrid
 {
+    /// <summary>
+    /// The items list that forms the source for the rows of this grid
+    /// </summary>
+    /// <remarks>
+    /// <b>Note:</b> This must be a list of type <see cref="List{T}"/>, otherwise the assignment to this property <u>will not</u> work.
+    /// </remarks>
+    IList Items { get; set; }
+}
 
-    public interface IDynamicItemsListGrid : IDynamicGrid
-    {
-        IList Items { get; set; }
-        
-        
-    }
+public class DynamicItemsListGrid<T> : DynamicGrid<T>, IDynamicItemsListGrid
+    where T : BaseObject, new()
+{
     
-    public class DynamicItemsListGrid<T> : DynamicGrid<T>, IDynamicItemsListGrid
-        where T : BaseObject, new()
-    {
-        
-        private List<T> _items = new List<T>();
+    private List<T> _items = [];
 
-        public List<T> Items 
-        { 
-            get => _items; 
-            set => _items = value; 
-        }
+    public List<T> Items
+    { 
+        get => _items; 
+        set => _items = value; 
+    }
 
-        IList IDynamicItemsListGrid.Items
-        {
-            get => _items; 
-            set => _items = value as List<T> ?? new List<T>();
-        }
+    IList IDynamicItemsListGrid.Items
+    {
+        get => _items; 
+        set => _items = value as List<T> ?? new List<T>();
+    }
 
-        protected override void Init()
-        {
-        }
+    protected override void Init()
+    {
+    }
 
-        protected override void DoReconfigure(DynamicGridOptions options)
-        {
-            
-        }
+    protected override void DoReconfigure(DynamicGridOptions options)
+    {
+        
+    }
 
-        public override void DeleteItems(params CoreRow[] rows)
+    public override void DeleteItems(params CoreRow[] rows)
+    {
+        foreach (var row in rows.OrderByDescending(x => x.Index))
         {
-            foreach (var row in rows.OrderByDescending(x => x.Index))
-            {
-                Items.RemoveAt(_recordmap[row].Index);
-            }
+            Items.RemoveAt(_recordmap[row].Index);
         }
+    }
 
-        public override T LoadItem(CoreRow row)
-        {
-            return Items[_recordmap[row].Index];
-        }
+    public override T LoadItem(CoreRow row)
+    {
+        return Items[_recordmap[row].Index];
+    }
 
-        protected override void Reload(Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sort, Action<CoreTable?, Exception?> action)
-        {
-            var result = new CoreTable();
-            result.LoadColumns(columns);
-            result.LoadRows(Items);
-            action.Invoke(result, null);
-        }
+    protected override void Reload(Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sort, Action<CoreTable?, Exception?> action)
+    {
+        var result = new CoreTable();
+        result.LoadColumns(columns);
+        result.LoadRows(Items);
+        action.Invoke(result, null);
+    }
 
-        public override void SaveItem(T item)
+    public override void SaveItem(T item)
+    {
+        if (!Items.Contains(item))
         {
-            if (!Items.Contains(item))
-            {
-                Items.Add(item);
-            }
+            Items.Add(item);
         }
-
     }
 
 }

+ 275 - 239
inabox.wpf/WPFUtils.cs

@@ -9,304 +9,340 @@ using System.Windows.Media;
 using InABox.Core;
 using Image = System.Windows.Controls.Image;
 
-namespace InABox.WPF
+namespace InABox.WPF;
+
+public class FuncTemplateSelector : DataTemplateSelector
 {
-    public static class WPFUtils
+    public Func<object, DependencyObject, FrameworkElement?> TemplateFunc { get; set; }
+
+    public FuncTemplateSelector(Func<object, DependencyObject, FrameworkElement?> templateFunc)
     {
-        public static void Bind<T, TProperty>(
-            this FrameworkElement element, 
-            DependencyProperty property, 
-            Expression<Func<T, TProperty>> expression, 
-            IValueConverter? converter = null,
-            BindingMode mode = BindingMode.Default,
-            string? format = null )
-        {
-            element.SetBinding(
-                property,
-                new Binding(CoreUtils.GetFullPropertyName(expression, "_"))
-                {
-                    Converter = converter,
-                    StringFormat = format,
-                    Mode = mode
-                }
-            );
-        }
-        
-        
-        public static T? FindLogicalParent<T>(this DependencyObject dependencyObject)
-            where T : DependencyObject
-        {
-            DependencyObject? parent = dependencyObject; 
-            do
-            {
-                parent = LogicalTreeHelper.GetParent(parent);
-            } while(parent != null && parent is not T);
-            return parent as T;
-        }
+        TemplateFunc = templateFunc;
+    }
 
-        public static int GetRow(this Grid grid, DependencyObject dependencyObject)
+    public override DataTemplate SelectTemplate(object item, DependencyObject container)
+    {
+        return TemplateGenerator.CreateDataTemplate(() =>
         {
-            while (true)
-            {
-                var parent = LogicalTreeHelper.GetParent(dependencyObject);
-                if (parent == null)
-                    return -1;
-                if (parent == grid)
-                    return Grid.GetRow(dependencyObject as UIElement);
-                dependencyObject = parent;
-            }
-        }
+            return TemplateFunc(item, container);
+        });
+    }
+}
 
-        public static int GetRowSpan(this Grid grid, DependencyObject dependencyObject)
-        {
-            while (true)
-            {
-                var parent = LogicalTreeHelper.GetParent(dependencyObject);
-                if (parent == null)
-                    return -1;
-                if (parent == grid)
-                    return Grid.GetRowSpan(dependencyObject as UIElement);
-                dependencyObject = parent;
-            }
-        }
-       
-        public static int GetColumn(this Grid grid, DependencyObject dependencyObject)
-        {
-            while (true)
+public static class WPFUtils
+{
+    public static void Bind<T, TProperty>(
+        this FrameworkElement element,
+        DependencyProperty property,
+        T source,
+        Expression<Func<T, TProperty>> expression,
+        IValueConverter? converter = null,
+        string? format = null)
+    {
+        element.SetBinding(
+            property,
+            new Binding(CoreUtils.GetFullPropertyName(expression, "_"))
             {
-                var parent = LogicalTreeHelper.GetParent(dependencyObject);
-                if (parent == null)
-                    return -1;
-                if (parent == grid)
-                    return Grid.GetColumn(dependencyObject as UIElement);
-                dependencyObject = parent;
+                Source = source,
+                Converter = converter,
+                StringFormat = format
             }
-        }
+        );
+    }
 
-        public static int GetColumnSpan(this Grid grid, DependencyObject dependencyObject)
-        {
-            while (true)
+    public static void Bind<T, TProperty>(
+        this FrameworkElement element, 
+        DependencyProperty property, 
+        Expression<Func<T, TProperty>> expression, 
+        IValueConverter? converter = null,
+        BindingMode mode = BindingMode.Default,
+        string? format = null )
+    {
+        element.SetBinding(
+            property,
+            new Binding(CoreUtils.GetFullPropertyName(expression, "_"))
             {
-                var parent = LogicalTreeHelper.GetParent(dependencyObject);
-                if (parent == null)
-                    return -1;
-                if (parent == grid)
-                    return Grid.GetColumnSpan(dependencyObject as UIElement);
-                dependencyObject = parent;
+                Converter = converter,
+                StringFormat = format,
+                Mode = mode
             }
-        }
-       
-        public static void SetGridPosition(this FrameworkElement element, int row, int column, int rowspan = 1, int colspan = 1)
-        {
-            element.SetValue(Grid.ColumnProperty, column);
-            element.SetValue(Grid.ColumnSpanProperty, Math.Max(1, colspan));
-            element.SetValue(Grid.RowProperty, row);
-            element.SetValue(Grid.RowSpanProperty, Math.Max(1, rowspan));
-        }
-        public static Grid AddChild(this Grid grid, FrameworkElement element, int row, int column, int rowSpan = 1, int colSpan = 1)
+        );
+    }
+    
+    
+    public static T? FindLogicalParent<T>(this DependencyObject dependencyObject)
+        where T : DependencyObject
+    {
+        DependencyObject? parent = dependencyObject; 
+        do
         {
-            element.SetGridPosition(row, column, rowSpan, colSpan);
-            grid.Children.Add(element);
-            return grid;
-        }
+            parent = LogicalTreeHelper.GetParent(parent);
+        } while(parent != null && parent is not T);
+        return parent as T;
+    }
 
-        public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
+    public static int GetRow(this Grid grid, DependencyObject dependencyObject)
+    {
+        while (true)
         {
-            if (depObj != null)
-                //ContentControl cc = depObj as ContentControl;
-                //if (cc != null)
-                //{
-                //    if (cc.Content == null)
-                //        yield return null;
-                //    if (cc.Content is T)
-                //        yield return cc.Content as T;
-                //    foreach (var child in FindVisualChildren<T>(cc.Content as DependencyObject))
-                //        yield return child;
-                //}
-                //else
-                for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
-                {
-                    var child = VisualTreeHelper.GetChild(depObj, i);
-                    if (child is null)
-                        continue;
-
-                    if (child is T t)
-                        yield return t;
-
-                    foreach (var childOfChild in FindVisualChildren<T>(child))
-                        yield return childOfChild;
-                }
+            var parent = LogicalTreeHelper.GetParent(dependencyObject);
+            if (parent == null)
+                return -1;
+            if (parent == grid)
+                return Grid.GetRow(dependencyObject as UIElement);
+            dependencyObject = parent;
         }
+    }
 
-        #region Grid Columns + Rows
-
-        public static ColumnDefinition AddColumn(this Grid grid, GridUnitType type, double value = 1)
+    public static int GetRowSpan(this Grid grid, DependencyObject dependencyObject)
+    {
+        while (true)
         {
-            var colDef = new ColumnDefinition { Width = new GridLength(value, type) };
-            grid.ColumnDefinitions.Add(colDef);
-            return colDef;
+            var parent = LogicalTreeHelper.GetParent(dependencyObject);
+            if (parent == null)
+                return -1;
+            if (parent == grid)
+                return Grid.GetRowSpan(dependencyObject as UIElement);
+            dependencyObject = parent;
         }
-        public static ColumnDefinition AddColumn(this Grid grid, double value)
+    }
+   
+    public static int GetColumn(this Grid grid, DependencyObject dependencyObject)
+    {
+        while (true)
         {
-            var colDef = new ColumnDefinition { Width = new GridLength(value) };
-            grid.ColumnDefinitions.Add(colDef);
-            return colDef;
+            var parent = LogicalTreeHelper.GetParent(dependencyObject);
+            if (parent == null)
+                return -1;
+            if (parent == grid)
+                return Grid.GetColumn(dependencyObject as UIElement);
+            dependencyObject = parent;
         }
+    }
 
-        public static RowDefinition AddRow(this Grid grid, GridUnitType type, double value = 1)
-        {
-            var rowDef = new RowDefinition { Height = new GridLength(value, type) };
-            grid.RowDefinitions.Add(rowDef);
-            return rowDef;
-        }
-        public static RowDefinition AddRow(this Grid grid, double value)
+    public static int GetColumnSpan(this Grid grid, DependencyObject dependencyObject)
+    {
+        while (true)
         {
-            var rowDef = new RowDefinition { Height = new GridLength(value) };
-            grid.RowDefinitions.Add(rowDef);
-            return rowDef;
+            var parent = LogicalTreeHelper.GetParent(dependencyObject);
+            if (parent == null)
+                return -1;
+            if (parent == grid)
+                return Grid.GetColumnSpan(dependencyObject as UIElement);
+            dependencyObject = parent;
         }
+    }
+   
+    public static void SetGridPosition(this FrameworkElement element, int row, int column, int rowspan = 1, int colspan = 1)
+    {
+        element.SetValue(Grid.ColumnProperty, column);
+        element.SetValue(Grid.ColumnSpanProperty, Math.Max(1, colspan));
+        element.SetValue(Grid.RowProperty, row);
+        element.SetValue(Grid.RowSpanProperty, Math.Max(1, rowspan));
+    }
+    public static Grid AddChild(this Grid grid, FrameworkElement element, int row, int column, int rowSpan = 1, int colSpan = 1)
+    {
+        element.SetGridPosition(row, column, rowSpan, colSpan);
+        grid.Children.Add(element);
+        return grid;
+    }
 
-        #endregion
+    public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
+    {
+        if (depObj != null)
+            //ContentControl cc = depObj as ContentControl;
+            //if (cc != null)
+            //{
+            //    if (cc.Content == null)
+            //        yield return null;
+            //    if (cc.Content is T)
+            //        yield return cc.Content as T;
+            //    foreach (var child in FindVisualChildren<T>(cc.Content as DependencyObject))
+            //        yield return child;
+            //}
+            //else
+            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
+            {
+                var child = VisualTreeHelper.GetChild(depObj, i);
+                if (child is null)
+                    continue;
 
-        #region Menu Utils
+                if (child is T t)
+                    yield return t;
 
-        private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index)
-        {
-            if (index != -1)
-            {
-                menu.Items.Insert(index, item);
+                foreach (var childOfChild in FindVisualChildren<T>(child))
+                    yield return childOfChild;
             }
-            else
-            {
-                menu.Items.Add(item);
-            }
-        }
+    }
 
-        private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, bool enabled, int index = -1)
-        {
-            var item = new MenuItem { Header = caption, IsEnabled = enabled };
-            if (image != null)
-                item.Icon = new Image() { Source = enabled ? image.AsBitmapImage(24, 24) : image.AsGrayScale().AsBitmapImage(24, 24) };
+    #region Grid Columns + Rows
 
-            ItemsControlInsert(menu, item, index);
-            return item;
-        }
+    public static ColumnDefinition AddColumn(this Grid grid, GridUnitType type, double value = 1)
+    {
+        var colDef = new ColumnDefinition { Width = new GridLength(value, type) };
+        grid.ColumnDefinitions.Add(colDef);
+        return colDef;
+    }
+    public static ColumnDefinition AddColumn(this Grid grid, double value)
+    {
+        var colDef = new ColumnDefinition { Width = new GridLength(value) };
+        grid.ColumnDefinitions.Add(colDef);
+        return colDef;
+    }
 
-        private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, Action? click, bool enabled, int index = -1)
-        {
-            var item = DoAddMenuItem(menu, caption, image, enabled, index);
+    public static RowDefinition AddRow(this Grid grid, GridUnitType type, double value = 1)
+    {
+        var rowDef = new RowDefinition { Height = new GridLength(value, type) };
+        grid.RowDefinitions.Add(rowDef);
+        return rowDef;
+    }
+    public static RowDefinition AddRow(this Grid grid, double value)
+    {
+        var rowDef = new RowDefinition { Height = new GridLength(value) };
+        grid.RowDefinitions.Add(rowDef);
+        return rowDef;
+    }
 
-            if (click != null)
-            {
-                item.Click += (o, e) =>
-                {
-                    click();
-                };
-            }
+    #endregion
 
-            return item;
+    #region Menu Utils
+
+    private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index)
+    {
+        if (index != -1)
+        {
+            menu.Items.Insert(index, item);
         }
-        private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled, int index = -1)
+        else
         {
-            var item = DoAddMenuItem(menu, caption, image, enabled, index);
+            menu.Items.Add(item);
+        }
+    }
 
-            item.Tag = tag;
-            item.Click += (o, e) =>
-            {
-                click((T)(o as MenuItem)!.Tag);
-            };
+    private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, bool enabled, int index = -1)
+    {
+        var item = new MenuItem { Header = caption, IsEnabled = enabled };
+        if (image != null)
+            item.Icon = new Image() { Source = enabled ? image.AsBitmapImage(24, 24) : image.AsGrayScale().AsBitmapImage(24, 24) };
 
-            return item;
-        }
+        ItemsControlInsert(menu, item, index);
+        return item;
+    }
 
-        public delegate void CheckToggleAction(bool isChecked);
-        public delegate void CheckToggleAction<T>(T tag, bool isChecked);
+    private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, Action? click, bool enabled, int index = -1)
+    {
+        var item = DoAddMenuItem(menu, caption, image, enabled, index);
 
-        private static MenuItem DoAddCheckItem(ItemsControl menu, string caption, CheckToggleAction click, bool isChecked, bool enabled, int index = -1)
+        if (click != null)
         {
-            var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };
-
             item.Click += (o, e) =>
             {
-                click(item.IsChecked);
+                click();
             };
-
-            ItemsControlInsert(menu, item, index);
-            return item;
         }
 
+        return item;
+    }
+    private static MenuItem DoAddMenuItem<T>(ItemsControl menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled, int index = -1)
+    {
+        var item = DoAddMenuItem(menu, caption, image, enabled, index);
 
-        private static MenuItem DoAddCheckItem<T>(ItemsControl menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked, bool enabled, int index = -1)
+        item.Tag = tag;
+        item.Click += (o, e) =>
         {
-            var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };
+            click((T)(o as MenuItem)!.Tag);
+        };
 
-            item.Tag = tag;
-            item.Click += (o, e) =>
-            {
-                click((T)(o as MenuItem)!.Tag, item.IsChecked);
-            };
+        return item;
+    }
 
-            ItemsControlInsert(menu, item, index);
-            return item;
-        }
+    public delegate void CheckToggleAction(bool isChecked);
+    public delegate void CheckToggleAction<T>(T tag, bool isChecked);
+
+    private static MenuItem DoAddCheckItem(ItemsControl menu, string caption, CheckToggleAction click, bool isChecked, bool enabled, int index = -1)
+    {
+        var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };
 
-        private static Separator DoAddSeparator(ItemsControl menu, int index)
+        item.Click += (o, e) =>
         {
-            var separator = new Separator();
+            click(item.IsChecked);
+        };
 
-            ItemsControlInsert(menu, separator, index);
+        ItemsControlInsert(menu, item, index);
+        return item;
+    }
 
-            return separator;
-        }
-        private static Separator? DoAddSeparatorIfNeeded(ItemsControl menu, int index)
+
+    private static MenuItem DoAddCheckItem<T>(ItemsControl menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked, bool enabled, int index = -1)
+    {
+        var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked };
+
+        item.Tag = tag;
+        item.Click += (o, e) =>
         {
-            if (menu.Items.Count == 0) return null;
+            click((T)(o as MenuItem)!.Tag, item.IsChecked);
+        };
 
-            var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1;
-            if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null;
+        ItemsControlInsert(menu, item, index);
+        return item;
+    }
 
-            var last = menu.Items[lastIndex];
-            if (last is Separator) return null;
+    private static Separator DoAddSeparator(ItemsControl menu, int index)
+    {
+        var separator = new Separator();
 
-            var separator = new Separator();
+        ItemsControlInsert(menu, separator, index);
 
-            ItemsControlInsert(menu, separator, index);
+        return separator;
+    }
+    private static Separator? DoAddSeparatorIfNeeded(ItemsControl menu, int index)
+    {
+        if (menu.Items.Count == 0) return null;
 
-            return separator;
-        }
+        var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1;
+        if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null;
 
-        private static void DoRemoveUnnecessarySeparators(ItemsControl menu)
+        var last = menu.Items[lastIndex];
+        if (last is Separator) return null;
+
+        var separator = new Separator();
+
+        ItemsControlInsert(menu, separator, index);
+
+        return separator;
+    }
+
+    private static void DoRemoveUnnecessarySeparators(ItemsControl menu)
+    {
+        while(menu.Items.Count > 0 && menu.Items[0] is Separator)
         {
-            while(menu.Items.Count > 0 && menu.Items[0] is Separator)
-            {
-                menu.Items.RemoveAt(0);
-            }
-            while(menu.Items.Count > 0 && menu.Items[^1] is Separator)
-            {
-                menu.Items.RemoveAt(menu.Items.Count - 1);
-            }
+            menu.Items.RemoveAt(0);
+        }
+        while(menu.Items.Count > 0 && menu.Items[^1] is Separator)
+        {
+            menu.Items.RemoveAt(menu.Items.Count - 1);
         }
-
-        public static Separator AddSeparator(this ContextMenu menu, int index = -1) => DoAddSeparator(menu, index);
-        public static Separator AddSeparator(this MenuItem menu, int index = -1) => DoAddSeparator(menu, index);
-        public static Separator? AddSeparatorIfNeeded(this ContextMenu menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
-        public static Separator? AddSeparatorIfNeeded(this MenuItem menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
-        public static void RemoveUnnecessarySeparators(this ContextMenu menu) => DoRemoveUnnecessarySeparators(menu);
-        public static void RemoveUnnecessarySeparators(this MenuItem menu) => DoRemoveUnnecessarySeparators(menu);
-
-        public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
-            => DoAddMenuItem(menu, caption, image, click, enabled, index);
-        public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
-            => DoAddMenuItem(menu, caption, image, click, enabled, index);
-        public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
-            => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
-        public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
-            => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
-        public static MenuItem AddCheckItem(this ContextMenu menu, string caption, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1)
-            => DoAddCheckItem(menu, caption, click, isChecked, enabled, index);
-        public static MenuItem AddCheckItem<T>(this ContextMenu menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked = false, bool enabled = true, int index = -1)
-            => DoAddCheckItem(menu, caption, tag, click, isChecked, enabled, index);
-
-        #endregion
     }
+
+    public static Separator AddSeparator(this ContextMenu menu, int index = -1) => DoAddSeparator(menu, index);
+    public static Separator AddSeparator(this MenuItem menu, int index = -1) => DoAddSeparator(menu, index);
+    public static Separator? AddSeparatorIfNeeded(this ContextMenu menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
+    public static Separator? AddSeparatorIfNeeded(this MenuItem menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index);
+    public static void RemoveUnnecessarySeparators(this ContextMenu menu) => DoRemoveUnnecessarySeparators(menu);
+    public static void RemoveUnnecessarySeparators(this MenuItem menu) => DoRemoveUnnecessarySeparators(menu);
+
+    public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
+        => DoAddMenuItem(menu, caption, image, click, enabled, index);
+    public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1)
+        => DoAddMenuItem(menu, caption, image, click, enabled, index);
+    public static MenuItem AddItem<T>(this ContextMenu menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
+        => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
+    public static MenuItem AddItem<T>(this MenuItem menu, string caption, Bitmap? image, T tag, Action<T> click, bool enabled = true, int index = -1)
+        => DoAddMenuItem(menu, caption, image, tag, click, enabled, index);
+    public static MenuItem AddCheckItem(this ContextMenu menu, string caption, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1)
+        => DoAddCheckItem(menu, caption, click, isChecked, enabled, index);
+    public static MenuItem AddCheckItem<T>(this ContextMenu menu, string caption, T tag, CheckToggleAction<T> click, bool isChecked = false, bool enabled = true, int index = -1)
+        => DoAddCheckItem(menu, caption, tag, click, isChecked, enabled, index);
+
+    #endregion
 }