using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace RQOverlay; /// bool -> Visibility. ConverterParameter="!" инвертирует. public sealed class BoolToVis : IValueConverter { public object Convert(object value, Type t, object? p, CultureInfo c) { bool v = value is true; if (p as string == "!") v = !v; return v ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type t, object? p, CultureInfo c) => throw new NotSupportedException(); } /// /// Панель-полоска: делит ширину между детьми пропорционально их весу /// (присоединённое свойство Weight). Для полоски долей дохода. /// public sealed class ShareStrip : Panel { public static readonly DependencyProperty WeightProperty = DependencyProperty.RegisterAttached( "Weight", typeof(double), typeof(ShareStrip), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsParentArrange)); public static double GetWeight(DependencyObject o) => (double)o.GetValue(WeightProperty); public static void SetWeight(DependencyObject o, double v) => o.SetValue(WeightProperty, v); protected override Size MeasureOverride(Size available) { foreach (UIElement child in InternalChildren) child.Measure(available); return new Size(0, 0); // растягиваемся на всё, что дадут } protected override Size ArrangeOverride(Size final) { double total = InternalChildren.Cast().Sum(c => Math.Max(0, GetWeight(c))); double x = 0; foreach (UIElement child in InternalChildren) { double w = total > 0 ? final.Width * Math.Max(0, GetWeight(child)) / total : 0; child.Arrange(new Rect(x, 0, w, final.Height)); x += w; } return final; } }