using System; using System.Collections.Generic; using System.Drawing; using System.Linq.Expressions; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using InABox.Core; using InABox.Wpf; using Image = System.Windows.Controls.Image; namespace InABox.WPF; public class FuncTemplateSelector : DataTemplateSelector { public Func TemplateFunc { get; set; } public FuncTemplateSelector(Func templateFunc) { TemplateFunc = templateFunc; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { return TemplateGenerator.CreateDataTemplate(() => { return TemplateFunc(item, container); }); } } public static class WPFUtils { public static Style AddSetter(this Style style, DependencyProperty property, object value) { style.Setters.Add(new Setter(property, value)); return style; } public static DataTrigger AddSetter(this DataTrigger trigger, DependencyProperty property, object value) { trigger.Setters.Add(new Setter(property, value)); return trigger; } public static DataTrigger AddDataTrigger(this Style style) { var trigger = new DataTrigger(); style.Triggers.Add(trigger); return trigger; } public static DataTrigger AddDataTrigger(this Style style, Binding binding, object value) { var trigger = new DataTrigger() { Binding = binding, Value = value }; style.Triggers.Add(trigger); return trigger; } public static SolidColorBrush ToBrush(this System.Windows.Media.Color color, double opacity = 1.0) { return new SolidColorBrush(color) { Opacity = opacity }; } #region Multi-Binding public static MultiBinding CreateMultiBinding(IMultiValueConverter? converter = null, string? format = null, object? parameter = null) { return new MultiBinding { Converter = converter, ConverterParameter = parameter, StringFormat = format }; } public static MultiBinding AddBinding(this MultiBinding multi, BindingBase binding) { multi.Bindings.Add(binding); return multi; } #endregion #region Binding public static Binding CreateBinding( T source, Expression> expression, IValueConverter? converter, string? format) { return new Binding(CoreUtils.GetFullPropertyName(expression, "_")) { Source = source, Converter = converter, StringFormat = format }; } public static Binding CreateBinding( Expression> expression, IValueConverter? converter, BindingMode mode, string? format) { return new Binding(CoreUtils.GetFullPropertyName(expression, "_")) { Converter = converter, StringFormat = format, Mode = mode }; } public static DataTrigger Bind( this DataTrigger trigger, T source, Expression> expression, TValue value, IValueConverter? converter, string? format = null) { trigger.Binding = CreateBinding(source, expression, converter, format); trigger.Value = value; return trigger; } public static DataTrigger Bind( this DataTrigger trigger, Expression> expression, TValue value, IValueConverter? converter, BindingMode mode = BindingMode.Default, string? format = null) { trigger.Binding = CreateBinding(expression, converter, mode, format); trigger.Value = value; return trigger; } public static DataTrigger Bind( this DataTrigger trigger, T source, Expression> expression, TProperty value, IValueConverter? converter = null, string? format = null) { trigger.Binding = CreateBinding(source, expression, converter, format); trigger.Value = value; return trigger; } public static DataTrigger Bind( this DataTrigger trigger, Expression> expression, TProperty value, IValueConverter? converter = null, BindingMode mode = BindingMode.Default, string? format = null) { trigger.Binding = CreateBinding(expression, converter, mode, format); trigger.Value = value; return trigger; } public static void Bind( this FrameworkElement element, DependencyProperty property, T source, Expression> expression, IValueConverter? converter = null, string? format = null) { element.SetBinding( property, CreateBinding(source, expression, converter, format) ); } public static void Bind( this FrameworkElement element, DependencyProperty property, Expression> expression, IValueConverter? converter = null, BindingMode mode = BindingMode.Default, string? format = null ) { element.SetBinding( property, CreateBinding(expression, converter, mode, format) ); } #endregion #region Converters public static IMultiValueConverter WrapConverter(this IValueConverter converter, Func convert, Func? convertBack = null) { return new MultiFuncConverter(convert, convertBack, converter); } #endregion public static T? FindLogicalParent(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; } public static IEnumerable FindVisualChildren(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(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(child)) yield return childOfChild; } } #region Grid Children public static int GetRow(this Grid grid, DependencyObject dependencyObject) { while (true) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetRow(dependencyObject as UIElement); dependencyObject = parent; } } 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) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetColumn(dependencyObject as UIElement); dependencyObject = parent; } } public static int GetColumnSpan(this Grid grid, DependencyObject dependencyObject) { while (true) { 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 #region Grid Columns + Rows 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; } 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; } #endregion #region Menu Utils private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index) { if (index != -1) { menu.Items.Insert(index, item); } 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) }; ItemsControlInsert(menu, item, index); return item; } 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); if (click != null) { item.Click += (o, e) => { click(); }; } return item; } private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, T tag, Action click, bool enabled, int index = -1) { var item = DoAddMenuItem(menu, caption, image, enabled, index); item.Tag = tag; item.Click += (o, e) => { click((T)(o as MenuItem)!.Tag); }; return item; } public delegate void CheckToggleAction(bool isChecked); public delegate void CheckToggleAction(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 }; item.Click += (o, e) => { click(item.IsChecked); }; ItemsControlInsert(menu, item, index); return item; } private static MenuItem DoAddCheckItem(ItemsControl menu, string caption, T tag, CheckToggleAction 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) => { click((T)(o as MenuItem)!.Tag, item.IsChecked); }; ItemsControlInsert(menu, item, index); return item; } private static Separator DoAddSeparator(ItemsControl menu, int index) { var separator = new Separator(); ItemsControlInsert(menu, separator, index); return separator; } private static Separator? DoAddSeparatorIfNeeded(ItemsControl menu, int index) { if (menu.Items.Count == 0) return null; var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1; if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null; 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) { 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(this ContextMenu menu, string caption, Bitmap? image, T tag, Action click, bool enabled = true, int index = -1) => DoAddMenuItem(menu, caption, image, tag, click, enabled, index); public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, T tag, Action 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(this ContextMenu menu, string caption, T tag, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1) => DoAddCheckItem(menu, caption, tag, click, isChecked, enabled, index); #endregion }