public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePropertyName) { var viewModelObservableProperty = viewModel.GetType().GetProperty(observablePropertyName); if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePropertyName}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } viewModel.SynchronizeForLifetime(observablePropertyName, () => { var newValue = viewModelObservableProperty.GetValue(viewModel); if (newValue == latestValue) { return; } latestValue = newValue; controlProperty.SetValue(control, newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) { return; } latestValue = newValue; viewModelObservableProperty.SetValue(viewModel, newValue); }, control.LifetimeManager); }
public static T FillAndPreserveAspectRatio <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl { parent = parent ?? child.Parent; var effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0); Action syncAction = () => { if (parent.Width == 0 || parent.Height == 0) { return; } var aspectRatio = (float)child.Width / child.Height; var newW = parent.Width - (effectivePadding.Left + effectivePadding.Right); var newH = (int)Math.Round(newW / aspectRatio); if (newH > parent.Height) { newH = parent.Height; newW = (int)Math.Round(newH * aspectRatio); } var newLeft = (parent.Width - newW) / 2; var newTop = (parent.Height - newH) / 2; child.Bounds = new Rectangle(newLeft, newTop, newW, newH); }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T Fill <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl { parent = parent ?? child.Parent; var effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0); Action syncAction = () => { if (parent.Width == 0 || parent.Height == 0) { return; } var newBounds = new Rectangle(new Point(0, 0), parent.Size); newBounds.X += effectivePadding.Left; newBounds.Width -= effectivePadding.Left; newBounds.Width -= effectivePadding.Right; newBounds.Y += effectivePadding.Top; newBounds.Height -= effectivePadding.Top; newBounds.Height -= effectivePadding.Bottom; child.Bounds = newBounds; }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T FillVertically <T>(this T child, ConsoleControl parent = null) where T : ConsoleControl { parent = parent ?? child.Parent; Action syncAction = () => { child.Bounds = new Rectangle(child.X, 0, child.Width, parent.Height); }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent.LifetimeManager); syncAction(); return(child); }
public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePath, Func <object, object> mapper, Func <object, object> reverseMapper) { this.mapper = mapper; this.reverseMapper = reverseMapper; var exp = ObjectPathExpression.Parse(observablePath); var trace = exp.EvaluateAndTraceInfo(viewModel); var observableObject = trace[trace.Count - 2].Value as ObservableObject; var viewModelObservableProperty = trace.Last()?.MemberInfo as PropertyInfo; if (observableObject == null) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePath}' is not observable"); } if (viewModelObservableProperty == null) { throw new InvalidOperationException($"Cannot resolve ViewModel property '{viewModel.GetType().FullName}.{observablePath}'"); } if (mapper != null && reverseMapper != null) { if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel type '{viewModel.GetType().FullName} property {observablePath}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } } observableObject.SynchronizeForLifetime(trace.Last().MemberInfo.Name, () => { var newValue = viewModelObservableProperty.GetValue(observableObject); if (newValue == latestValue) { return; } latestValue = newValue; controlProperty.SetValue(control, mapper != null ? mapper(newValue) : newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) { return; } latestValue = newValue; viewModelObservableProperty.SetValue(observableObject, reverseMapper != null ? reverseMapper(newValue) : newValue); }, control.LifetimeManager); }
public static T DockToLeft <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl { parent = parent ?? child.Parent; Action syncAction = () => { child.X = padding; }; child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T FillVertically <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl { parent = parent ?? child.Parent; var effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0); Action syncAction = () => { child.Bounds = new Rectangle(child.X, effectivePadding.Top, child.Width, parent.Height - (effectivePadding.Top + effectivePadding.Bottom)); }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T DockToBottom <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl { parent = parent ?? child.Parent; Action syncAction = () => { if (parent.Height == 0) { return; } child.Y = parent.Height - child.Height - padding; }; child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T FillHorizontally <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl { parent = parent ?? child.Parent; var effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0); Action syncAction = () => { if (parent.Width == 0) { return; } child.Bounds = new Rectangle(effectivePadding.Left, child.Y, parent.Width - (effectivePadding.Right + effectivePadding.Left), child.Height); }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
public static T DockToRight <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl { parent = parent ?? child.Parent; Action syncAction = () => { if (parent.Width == 0 || child.Width == 0) { return; } child.X = parent.Width - child.Width - padding; }; child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent.LifetimeManager); parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent.LifetimeManager); syncAction(); return(child); }
/// <summary> /// Adds the current control to the current focus context /// </summary> /// <param name="c">The control to add</param> internal void Add(ConsoleControl c) { if (focusStack.Peek().Controls.Contains(c)) { throw new InvalidOperationException("Item already being tracked"); } focusStack.Peek().Controls.Add(c); if (c.Id != null && c.Id == currentFocusedControlId) { c.TryFocus(); } c.SubscribeForLifetime(nameof(c.CanFocus), () => { if (c.CanFocus == false && c.HasFocus) { TryMoveFocus(); } }, c); }
public static T CenterHorizontally <T>(this T child, ConsoleControl parent = null) where T : ConsoleControl { parent = parent ?? child.Parent; Action syncAction = () => { if (parent.Width == 0 || child.Width == 0) { return; } var gap = parent.Width - child.Width; var x = gap / 2; child.X = Math.Max(0, x); }; parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent); syncAction(); return(child); }
private void ScrollableControls_Added(ConsoleControl c) { c.SubscribeForLifetime(nameof(Bounds), UpdateScrollbars, c.LifetimeManager); }
public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePropertyName) { var viewModelObservableProperty = viewModel.GetType().GetProperty(observablePropertyName); if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType && viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false && viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false) { throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePropertyName}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} "); } viewModel.SynchronizeForLifetime(observablePropertyName, () => { var newValue = viewModelObservableProperty.GetValue(viewModel); if (newValue == latestValue) return; latestValue = newValue; controlProperty.SetValue(control, newValue); }, control.LifetimeManager); control.SubscribeForLifetime(controlProperty.Name, () => { var newValue = controlProperty.GetValue(control); if (newValue == latestValue) return; latestValue = newValue; viewModelObservableProperty.SetValue(viewModel, newValue); }, control.LifetimeManager); }