Implement Control ownership and nice to have interfaces.

This commit is contained in:
2026-09-07 22:40:58 +03:00
parent e46a13249b
commit 1100fac94b
3 changed files with 129 additions and 47 deletions
+64 -9
View File
@@ -1,6 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using Dashboard.Drawing;
using Dashboard.Events;
using Dashboard.Layout;
@@ -8,21 +10,21 @@ using Dashboard.Pal;
namespace Dashboard.Controls
{
public class Container : Control, IList<Control>, ILayoutContainer
public class Container : Control, IList<Control>, ILayoutContainer, INotifyCollectionChanged
{
private readonly List<Control> _controls = new List<Control>();
public ContainerLayoutInfo ContainerLayout { get; } = new ContainerLayoutInfo();
public int Count => _controls.Count;
public bool IsReadOnly => false;
public ContainerLayoutInfo ContainerLayout { get; } = new ContainerLayoutInfo();
ILayoutItem IReadOnlyList<ILayoutItem>.this[int index] => _controls[index];
public event EventHandler<ContainerChildAddedEventArgs>? ChildAdded;
public event EventHandler<ContainerChildRemovedEventArgs>? ChildRemoved;
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public Control this[int index]
{
@@ -30,6 +32,11 @@ namespace Dashboard.Controls
set => _controls[index] = value;
}
public Container()
{
ContainerLayout.PropertyChanged += OnContainerLayoutChanged;
}
protected override void ValidateLayout()
{
if (!IsLayoutEnabled || IsLayoutValid)
@@ -82,16 +89,17 @@ namespace Dashboard.Controls
SetParent(this, item);
_controls.Add(item);
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
OnChildAdded(item);
}
public void Clear()
{
foreach (Control control in this)
{
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, control));
OnChildRemoved(control, false);
}
_controls.Clear();
OnCollectionChanged(NotifyCollectionChangedAction.Reset);
}
public bool Contains(Control item)
@@ -109,7 +117,7 @@ namespace Dashboard.Controls
if (!_controls.Remove(item))
return false;
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, item));
OnChildRemoved(item);
return true;
}
@@ -123,17 +131,64 @@ namespace Dashboard.Controls
SetParent(this, item);
_controls.Insert(index, item);
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
OnChildAdded(item);
}
public void RemoveAt(int index)
{
Control child = _controls[index];
_controls.RemoveAt(index);
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, child));
OnChildRemoved(child);
}
protected override void OnOwnerChanged(Form value)
{
base.OnOwnerChanged(value);
foreach (Control control in this)
{
SetOwner(control, value);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
Clear();
}
ContainerLayout.PropertyChanged -= OnContainerLayoutChanged;
}
protected virtual void OnChildAdded(Control item)
{
SetOwner(item, Owner ?? null);
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
OnCollectionChanged(NotifyCollectionChangedAction.Add);
}
protected virtual void OnChildRemoved(Control control, bool notifyCollectionChanged = true)
{
SetOwner(control, null!);
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, control));
if (notifyCollectionChanged)
OnCollectionChanged(NotifyCollectionChangedAction.Remove);
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action)
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action));
}
private void OnContainerLayoutChanged(object? sender, PropertyChangedEventArgs ea)
{
OnPropertyChanged(nameof(ContainerLayout));
}
}
public class ContainerChildAddedEventArgs(Container parent, Control child) : EventArgs
+44 -21
View File
@@ -13,27 +13,33 @@ namespace Dashboard.Controls
{
public class Control : IEventListener, ILayoutItem, IDisposable
{
private Form? _owner = null;
public string? Id { get; set; }
public string? Id
{
get;
set => SetField(ref field, value);
}
public Form Owner
{
get => _owner ?? throw NoOwnerException;
get ;
protected set
{
_owner = value;
OnOwnerChanged(value);
SetField(ref field, value);
}
}
} = null!;
public Control? Parent { get; private set; } = null;
public Control? Parent
{
get;
private set => SetField(ref field, value);
} = null;
public bool Disposed { get; private set; }
public virtual Box2d ClientArea => Layout.ComputedBox;
public bool IsFocused => _owner?.FocusedControl == this;
public bool IsFocused => Owner?.FocusedControl == this;
public Brush Background { get; set; } = new SolidColorBrush(Color.Transparent);
public Brush BorderBrush { get; set; } = new SolidColorBrush(Color.Black);
public Brush Background { get; set => SetField(ref field, value); } = new SolidColorBrush(Color.Transparent);
public Brush BorderBrush { get; set => SetField(ref field, value); } = new SolidColorBrush(Color.Black);
public LayoutInfo Layout { get; } = new LayoutInfo();
public bool IsLayoutEnabled { get; private set; } = true;
@@ -49,6 +55,11 @@ namespace Dashboard.Controls
public event EventHandler? Disposing;
public event EventHandler? Resized;
public Control()
{
Layout.PropertyChanged += LayoutChanged;
}
public virtual Vector2 CalculateIntrinsicSize()
{
return Vector2.Zero;
@@ -74,7 +85,9 @@ namespace Dashboard.Controls
{
if (Disposed)
return;
Disposed = true;
Layout.PropertyChanged -= LayoutChanged;
Dispose(disposing);
@@ -134,23 +147,13 @@ namespace Dashboard.Controls
FocusLost?.Invoke(sender, EventArgs.Empty);
}
internal static void InvokeFocusGained(Form form, Control control)
{
control.OnFocusGained(form);
}
internal static void InvokeFocusLost(Form form, Control control)
{
control.OnFocusLost(form);
}
protected virtual void OnResize()
{
Resized?.Invoke(this, EventArgs.Empty);
InvalidateLayout();
}
private void OnOwnerChanged(Form value)
protected virtual void OnOwnerChanged(Form value)
{
OwnerChanged?.Invoke(this, EventArgs.Empty);
}
@@ -188,6 +191,26 @@ namespace Dashboard.Controls
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private void LayoutChanged(object? sender, PropertyChangedEventArgs ea)
{
OnPropertyChanged(nameof(Layout));
}
protected static Exception NoOwnerException => new Exception("No form owns this control");
internal static void InvokeFocusGained(Form form, Control control)
{
control.OnFocusGained(form);
}
internal static void InvokeFocusLost(Form form, Control control)
{
control.OnFocusLost(form);
}
private protected static void SetOwner(Control item, Form owner)
{
item.Owner = owner;
}
}
}
+21 -17
View File
@@ -1,6 +1,5 @@
using System;
using System.Drawing;
using System.Numerics;
using Dashboard.Drawing;
using Dashboard.Events;
using Dashboard.Pal;
@@ -10,20 +9,18 @@ namespace Dashboard.Controls
{
public class Form : Container, IForm
{
private string? _title = "Untitled Form";
public IWindow Window { get; }
public Image? WindowIcon { get; set; }
public string? Title
public string Title
{
get => _title;
get;
set
{
_title = value;
Window.Title = _title ?? "";
}
field = value;
Window.Title = field ?? "";
}
} = "Untitled Form";
public Control? FocusedControl { get; private set; } = null;
public override Box2d ClientArea
@@ -37,19 +34,11 @@ namespace Dashboard.Controls
{
Window = window;
Window.Form = this;
Window.Title = _title;
Window.Title = Title;
Window.EventRaised += WindowEventRaised;
Background = new SolidColorBrush(Color.SlateGray);
}
private void WindowEventRaised(object? sender, EventArgs e)
{
if (e is ResizeEventArgs)
{
InvalidateLayout();
}
}
public void Focus(Control control)
{
if (FocusedControl != null)
@@ -108,5 +97,20 @@ namespace Dashboard.Controls
break;
}
}
protected override void OnChildAdded(Control item)
{
base.OnChildAdded(item);
SetOwner(item, this);
}
private void WindowEventRaised(object? sender, EventArgs e)
{
if (e is ResizeEventArgs)
{
InvalidateLayout();
}
}
}
}