using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Input; using Artemis.Core.Plugins.DataModelExpansions.Attributes; using Stylet; namespace Artemis.UI.Shared.DataModelVisualization { public abstract class DataModelInputViewModel : DataModelInputViewModel { private bool _closed; private T _inputValue; protected DataModelInputViewModel(DataModelPropertyAttribute description, T initialValue) { Description = description; InputValue = initialValue; } public T InputValue { get => _inputValue; set => SetAndNotify(ref _inputValue, value); } public DataModelPropertyAttribute Description { get; } internal override object InternalGuard { get; } = null; /// public sealed override void Submit() { if (_closed) return; _closed = true; foreach (var sourceUpdatingBinding in BindingOperations.GetSourceUpdatingBindings(View)) sourceUpdatingBinding.UpdateSource(); OnSubmit(); UpdateCallback(InputValue, true); } /// public sealed override void Cancel() { if (_closed) return; _closed = true; OnCancel(); UpdateCallback(InputValue, false); } } /// /// For internal use only, implement instead. /// public abstract class DataModelInputViewModel : PropertyChangedBase, IViewAware { /// /// Prevents this type being implemented directly, implement instead. /// // ReSharper disable once UnusedMember.Global internal abstract object InternalGuard { get; } internal Action UpdateCallback { get; set; } /// /// Gets the types this input view model can support through type conversion. This list is defined when registering the /// view model. /// internal IReadOnlyCollection CompatibleConversionTypes { get; set; } public void AttachView(UIElement view) { if (View != null) throw new InvalidOperationException(string.Format("Tried to attach View {0} to ViewModel {1}, but it already has a view attached", view.GetType().Name, GetType().Name)); View = view; // After the animation finishes attempt to focus the input field Task.Run(async () => { await Task.Delay(400); await Execute.OnUIThreadAsync(() => View.MoveFocus(new TraversalRequest(FocusNavigationDirection.First))); }); } public UIElement View { get; set; } /// /// Submits the input value and removes this view model. /// This is called automatically when the user presses enter or clicks outside the view /// public abstract void Submit(); /// /// Discards changes to the input value and removes this view model. /// This is called automatically when the user presses escape /// public abstract void Cancel(); /// /// Called before the current value is submitted /// protected virtual void OnSubmit() { } /// /// Called before the current value is discarded /// protected virtual void OnCancel() { } } }