aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs
blob: e55d0534eb40ff4ce50040f3403901072a8f8e88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core.Commands;
using Tango.BL.Entities;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.DB.Managers;
using Tango.SharedUI;
using System.Data.Entity.Infrastructure;
using Tango.MachineStudio.DB.Messages;
using System.Collections.ObjectModel;
using System.Reflection;
using Tango.MachineStudio.Common.StudioApplication;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using Tango.BL;
using Tango.Core.DI;
using Tango.Core.ExtensionMethods;

namespace Tango.MachineStudio.DB.ViewModels
{
    public abstract class DbTableViewModel<T> : ViewModel where T : class, IObservableEntity
    {
        protected INotificationProvider _notification;

        /// <summary>
        /// Initializes a new instance of the <see cref="DbTableViewModel"/> class.
        /// </summary>
        public DbTableViewModel(INotificationProvider notification) : base()
        {
            _notification = notification;
            Adapter = ObservablesEntitiesAdapter.Instance;
            ValidationErrors = new ObservableCollection<string>();

            AddCommand = new RelayCommand(OnAdd);
            EditCommand = new RelayCommand(OnEdit, (x) => SelectedEntity != null);
            DeleteCommand = new RelayCommand(OnDelete, (x) => SelectedEntity != null);
            DialogOKCommand = new RelayCommand(() => OnDialogOKPressed(DialogOpenMode, EditEntity));
            DialogCancelCommand = new RelayCommand(() => OnDialogCancelPressed(DialogOpenMode, EditEntity));

            IsDialogOpen = false;
        }

        private T _editEntity;
        /// <summary>
        /// Gets or sets the edit entity.
        /// </summary>
        public T EditEntity
        {
            get { return _editEntity; }
            set { _editEntity = value; RaisePropertyChangedAuto(); }
        }

        private DialogOpenMode _dialogOpenMode;
        /// <summary>
        /// Gets or sets the dialog open mode.
        /// </summary>
        public DialogOpenMode DialogOpenMode
        {
            get { return _dialogOpenMode; }
            set { _dialogOpenMode = value; RaisePropertyChangedAuto(); }
        }

        private bool _isDialogOpen;
        /// <summary>
        /// Gets or sets a value indicating whether this instance is dialog open.
        /// </summary>
        public bool IsDialogOpen
        {
            get { return _isDialogOpen; }
            set { _isDialogOpen = value; RaisePropertyChangedAuto(); }
        }

        private ObservablesEntitiesAdapter _adapter;
        /// <summary>
        /// Gets or sets the DB adapter.
        /// </summary>
        public ObservablesEntitiesAdapter Adapter
        {
            get { return _adapter; }
            set { _adapter = value; RaisePropertyChangedAuto(); }
        }

        private T _selectedEntity;
        /// <summary>
        /// Gets or sets the selected entity.
        /// </summary>
        public T SelectedEntity
        {
            get { return _selectedEntity; }
            set { _selectedEntity = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
        }

        private String _filter;
        /// <summary>
        /// Gets or sets the search filter.
        /// </summary>
        public String Filter
        {
            get { return _filter; }
            set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(value); }
        }

        /// <summary>
        /// Gets or sets the dialog OK command.
        /// </summary>
        public RelayCommand DialogOKCommand { get; set; }

        /// <summary>
        /// Gets or sets the dialog cancel command.
        /// </summary>
        public RelayCommand DialogCancelCommand { get; set; }

        /// <summary>
        /// Gets or sets the add command.
        /// </summary>
        public RelayCommand AddCommand { get; set; }

        /// <summary>
        /// Gets or sets the edit command.
        /// </summary>
        public RelayCommand EditCommand { get; set; }

        /// <summary>
        /// Gets or sets the delete command.
        /// </summary>
        public RelayCommand DeleteCommand { get; set; }

        protected override void OnValidating()
        {
            base.OnValidating();
            ValidationErrors.Clear();

            foreach (var prop in typeof(T).GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => !x.PropertyType.IsGenericType && x.PropertyType.IsClass && !x.Name.Contains("Guid")))
            {
                if (prop.GetValue(EditEntity) == null)
                {
                    ValidationErrors.Add(prop.Name + " is required");
                }
            }
        }

        /// <summary>
        /// Called when delete command invoked.
        /// </summary>
        protected virtual async void OnDelete()
        {
            using (_notification.PushTaskItem("Saving changes to database..."))
            {
                try
                {
                    SelectedEntity.Detach(Adapter.Context);
                    await Adapter.Context.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    Adapter.Invalidate();
                    _notification.ShowError("Could not delete entity." + Environment.NewLine + ex.Message);
                }

                SelectedEntity = null;
            }
        }

        /// <summary>
        /// Called when edit command invoked.
        /// </summary>
        protected virtual void OnEdit()
        {
            ValidationErrors.Clear();
            DialogOpenMode = DialogOpenMode.Editing;
            EditEntity = GetEditableEntity(DialogOpenMode);
            TangoMessenger.Default.Send(new OpenEntityEditViewMessage(DialogOpenMode, this, typeof(T)));
            IsDialogOpen = true;
        }

        /// <summary>
        /// Called when add command invoked.
        /// </summary>
        protected virtual void OnAdd()
        {
            ValidationErrors.Clear();
            DialogOpenMode = DialogOpenMode.Adding;
            EditEntity = GetEditableEntity(DialogOpenMode);

            var codeProp = EditEntity.GetType().GetProperty("Code");

            if (codeProp != null)
            {
                if (EditEntity.GetDbSet<T>(Adapter.Context).Count() > 0)
                {
                    int lastCode = EditEntity.GetDbSet<T>(Adapter.Context).ToList().Max(x => (int)codeProp.GetValue(x));
                    codeProp.SetValue(EditEntity, lastCode + 1);
                }
            }

            TangoMessenger.Default.Send(new OpenEntityEditViewMessage(DialogOpenMode, this, typeof(T)));
            IsDialogOpen = true;
        }

        /// <summary>
        /// Called when dialog closes with OK button.
        /// </summary>
        /// <param name="mode">The mode.</param>
        protected virtual async void OnDialogOKPressed(DialogOpenMode mode, T entity)
        {
            if (!Validate()) return;

            if (ValidationErrors.Count > 0) return;

            var codeProp = entity.GetType().GetProperty("Code");

            if (codeProp != null)
            {
                int code = (int)codeProp.GetValue(entity);

                if (entity.GetDbSet<T>(Adapter.Context).ToList().Where(x => x.Guid != entity.Guid).Select(x => (int)codeProp.GetValue(x)).Contains(code))
                {
                    _notification.ShowError("The entity code specified already exists.");
                    return;
                }
            }

            TangoMessenger.Default.Send(new CloseEntityEditViewMessage());

            if (mode == DialogOpenMode.Editing)
            {
                entity.ShallowCopyTo(SelectedEntity);
                entity = SelectedEntity;
            }

            OnBeforeEntitySave(mode, entity);

            using (_notification.PushTaskItem("Saving changes to database..."))
            {
                if (mode == DialogOpenMode.Adding)
                {
                    entity.Attach(Adapter.Context);
                }

                try
                {
                    await entity.SaveAsync(Adapter.Context);
                }
                catch (DbUpdateException ex)
                {
                    if (mode == DialogOpenMode.Adding)
                    {
                        entity.Detach(Adapter.Context);
                    }
                    Adapter.Invalidate();
                    _notification.ShowError("Could not save entity." + Environment.NewLine + ex.InnerException.InnerException != null ? ex.InnerException.InnerException.Message : ex.InnerException.Message);
                }
                catch (Exception)
                {
                    Adapter.Invalidate();
                    _notification.ShowError("Could not save entity." + Environment.NewLine + "Please make sure all fields are properly populated.");
                }
                IsDialogOpen = false;
                SelectedEntity = EditEntity;
                SelectedEntity = null;
            }
        }

        /// <summary>
        /// Called when [before entity save].
        /// </summary>
        /// <param name="mode">The mode.</param>
        /// <param name="entity">The entity.</param>
        protected virtual void OnBeforeEntitySave(DialogOpenMode mode, T entity)
        {

        }

        /// <summary>
        /// Called when dialog closes with cancel button.
        /// </summary>
        /// <param name="mode">The mode.</param>
        protected virtual void OnDialogCancelPressed(DialogOpenMode mode, T entity)
        {
            TangoMessenger.Default.Send(new CloseEntityEditViewMessage());
            IsDialogOpen = false;
        }

        /// <summary>
        /// Gets the editable entity.
        /// </summary>
        /// <param name="mode">The mode.</param>
        /// <returns></returns>
        private T GetEditableEntity(DialogOpenMode mode)
        {
            if (mode == DialogOpenMode.Adding)
            {
                var newEntity = Activator.CreateInstance<T>();
                InitializeEntity(newEntity);
                return newEntity;
            }
            else
            {
                return SelectedEntity.ShallowClone();
            }
        }

        protected virtual void OnFilterChanged(String filter)
        {
            String viewSourceName = this.GetType().Name.Replace("ViewVM", "ViewSource");
            ICollectionView collectionView = Adapter.GetType().GetProperty(viewSourceName).GetValue(Adapter) as ICollectionView;

            collectionView.Filter = (entity) =>
            {
                return FilterEntity((T)entity, filter);
            };
        }

        private bool FilterEntity(T entity, String filter)
        {
            foreach (var prop in entity.GetType().GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType.IsClass && x.PropertyType != typeof(String) && x.PropertyType != typeof(byte[]) && !x.PropertyType.IsGenericType))
            {
                object obj = prop.GetValue(entity);

                if (obj != null)
                {
                    foreach (var innerProp in obj.GetType().GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != "Deleted" && x.Name != "ID" && x.Name != "LastUpdated").Where(x => !x.PropertyType.IsGenericType && (x.PropertyType.IsClass || x.PropertyType == typeof(String))))
                    {
                        object value = innerProp.GetValue(obj);

                        if (value != null)
                        {
                            if (value.ToString().ToLower().Contains(filter.ToLower()))
                            {
                                return true;
                            }
                        }
                    }
                }
            }

            return
              entity.
              GetType().
              GetPropertiesWithAttribute<ColumnAttribute>(BindingFlags.Public | BindingFlags.Instance).
              Where(x => x.Name != "Deleted" && x.Name != "ID" && x.Name != "LastUpdated").
              Where(x => !x.PropertyType.IsGenericType && (x.PropertyType.IsClass || x.PropertyType == typeof(String))).
              Select(prop => prop.GetValue(entity).ToString()).
              ToList().
              Any(x => x.ToLower().Contains(filter.ToLower()));
        }

        protected virtual void InitializeEntity(T entity)
        {

        }
    }
}