using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; using net.sf.mpxj.mspdi.schema; using PRSDesktop.WidgetGroups; using PRS.Shared; using Syncfusion.Data.Extensions; using Syncfusion.UI.Xaml.Grid; using Syncfusion.UI.Xaml.Grid.Helpers; using Syncfusion.Windows.Tools.Controls; using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs; using System.Windows.Documents; using InABox.Wpf; namespace PRSDesktop; public class EmployeeResourcePlannerValue { public Guid[] IDs { get; set; } = Array.Empty(); public AssignmentModel[] Assignments = Array.Empty(); public Brush Background { get; set; } public Brush Foreground { get; set; } public String Text { get; set; } private String _color = ""; public String Color { get { return _color; } set { _color = value; var color = String.IsNullOrWhiteSpace(value) ? Colors.Transparent : (Color)ColorConverter.ConvertFromString(value); Background = new SolidColorBrush(color) { Opacity = 0.8 }; Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(color)); } } } public enum EmployeePlannerDisplayMode { EmployeeColumns, DateColumns } public class EmployeeResourcePlannerSettings : BaseObject, IGlobalConfigurationSettings { [EnumLookupEditor(typeof(EmployeePlannerDisplayMode))] [EditorSequence(1)] public EmployeePlannerDisplayMode DisplayMode { get; set; } public EmployeeResourcePlannerSettings() { DisplayMode = EmployeePlannerDisplayMode.DateColumns; } } public partial class EmployeeResourcePlanner : UserControl, IPropertiesPanel { private enum Suppress { This } private EmployeeResourceModel[] _employees = Array.Empty(); private StandardLeaveModel[] _standardleaves = Array.Empty(); private LeaveRequestModel[] _leaverequests = Array.Empty(); private JobModel[] _jobs = Array.Empty(); private ActivityModel[] _activities = Array.Empty(); private DateTime[] _dates = Array.Empty(); private CoreFilterDefinitions _jobfilters = new CoreFilterDefinitions(); public event LoadSettings LoadSettings; public event SaveSettings SaveSettings; EmployeeResourcePlannerSettings IPropertiesPanel.Properties { get => Settings; set => Settings = value; } private EmployeeResourcePlannerSettings Settings { get; set; } private void DoLoadSettings() { Properties = LoadSettings?.Invoke(this) ?? new EmployeeResourcePlannerProperties(); _jobfilters = new GlobalConfiguration("Job").Load(); } private void DoSaveSettings() { SaveSettings?.Invoke(this, Properties); } public EmployeeResourcePlannerProperties Properties { get; set; } public EmployeeResourcePlanner() { using (new EventSuppressor(Suppress.This)) InitializeComponent(); } private Filter? GetJobFilter() { var jobfilter = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter)); return !String.IsNullOrWhiteSpace(jobfilter?.Filter) ? Serialization.Deserialize>(jobfilter.Filter) : LookupFactory.DefineFilter(); } public void Setup() { using (new EventSuppressor(Suppress.This)) { DoLoadSettings(); EmployeeSelector.Setup(); EmployeeSelector.Settings = Properties.EmployeeSettings; EmployeeSelector.Selection = Properties.EmployeeSelection; ViewType.ItemsSource = Enum.GetValues() .Select(x => new KeyValuePair(x, x.ToString())); ViewType.SelectedValuePath = "Key"; ViewType.DisplayMemberPath = "Value"; ViewType.SelectedValue = Properties.ViewType; LeaveType.SelectedIndex = Properties.IncludeUnApprovedLeave ? 1 : 0; FromDate.DateTime = DateTime.Today; ToDate.DateTime = DateTime.Today.AddYears(1); MultiQuery query = new MultiQuery(); query.Add( GetJobFilter(), JobModel.Columns, new SortOrder(x => x.JobNumber) ); query.Add( null, StandardLeaveModel.Columns ); query.Add( new Filter(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected), LeaveRequestModel.Columns ); query.Add( LookupFactory.DefineFilter(), new Columns(x => x.ID).Add(x => x.Code).Add(x => x.Description), new SortOrder(x => x.Code) ); query.Query(); _jobs = query.Get().Rows.Select(r => new JobModel(r)).ToArray(); _standardleaves = query.Get().Rows.Select(r=>new StandardLeaveModel(r)).ToArray(); _leaverequests = query.Get().Rows.Select(r => new LeaveRequestModel(r)).ToArray(); _activities = query.Get().Rows.Select(r => new ActivityModel(r)).ToArray(); ActivityType.ItemsSource = _activities; ActivityType.SelectedValue = Properties.ActivityType; JobFilter.ItemsSource = _jobfilters; JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter)); } } public void Shutdown(CancelEventArgs? cancel) { } private TimeSpan GetPeriod() { return Properties.ViewType switch { EmployeeResourcePlannerViewType.Week => TimeSpan.FromDays(7), EmployeeResourcePlannerViewType.Day or _ => TimeSpan.FromDays(1) }; } public void Refresh() { using (new WaitCursor()) { _employees = EmployeeSelector.GetEmployeeData((row, rosters) => new EmployeeResourceModel(row, rosters)); var empids = _employees.Select(x => x.ID).ToArray(); DateTime fromdate = FromDate.DateTime.HasValue ? FromDate.DateTime.Value.Date : DateTime.Today; DateTime todate = ToDate.DateTime.HasValue ? ToDate.DateTime.Value.Date : DateTime.Today.AddYears(1); MultiQuery query = new MultiQuery(); var period = GetPeriod(); if(Properties.ViewType == EmployeeResourcePlannerViewType.Week) { fromdate = fromdate.AddDays(-(((int)fromdate.DayOfWeek - 1) % 7)); todate = todate.AddDays(-(((int)todate.DayOfWeek - 1) % 7)); } query.Add( new Filter(x => x.EmployeeLink.ID).InList(empids) .And(x => x.Date).IsGreaterThanOrEqualTo(fromdate) .And(x => x.Date).IsLessThanOrEqualTo(todate + period), AssignmentModel.Columns, new SortOrder(x => x.EmployeeLink.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending) ); query.Query(); var assignments = query.Get().Rows.Select(r => new AssignmentModel(r)).ToArray(); var data = new DataTable(); var standardHours = Properties.ViewType switch { EmployeeResourcePlannerViewType.Week => 38.0, EmployeeResourcePlannerViewType.Day or _ => 7.5 }; if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns) { data.Columns.Add("Date", typeof(DateTime)); foreach (var employee in _employees) { data.Columns.Add(employee.ID.ToString(), typeof(object)); } for (var curdate = fromdate; curdate <= todate; curdate += period) { var leavevalue = GetStandardLeave(curdate, _standardleaves); var values = new List { curdate }; foreach (var employee in _employees) { var value = new EmployeeResourcePlannerValue(); // Note use of short-circuiting here. var bOK = CheckAssignments(employee, curdate, curdate + period, assignments, value) || CheckStandardLeave(leavevalue, value) || CheckLeaveRequest(employee, curdate, curdate + period, _leaverequests, value) || CheckRoster(employee, curdate, curdate + period, standardHours, value); values.Add(value); } data.Rows.Add(values.ToArray()); } } else { data.Columns.Add("Employee", typeof(object)); var dates = new List(); for (var curdate = fromdate; curdate <= todate; curdate += period) { data.Columns.Add(dates.Count.ToString(), typeof(object)); dates.Add(curdate); } _dates = dates.ToArray(); foreach (var employee in _employees) { var values = new List { employee }; for (var curdate = fromdate; curdate <= todate; curdate += period) { var leavevalue = GetStandardLeave(curdate, _standardleaves); var value = new EmployeeResourcePlannerValue(); var bOK = CheckAssignments(employee, curdate, curdate + period, assignments, value) || CheckStandardLeave(leavevalue, value) || CheckLeaveRequest(employee, curdate, curdate + period, _leaverequests, value) || CheckRoster(employee, curdate, curdate + period, standardHours, value); values.Add(value); } data.Rows.Add(values.ToArray()); } } dataGrid.ItemsSource = data; } } private static bool CheckAssignments(EmployeeResourceModel employee, DateTime from, DateTime to, AssignmentModel[] assignments, EmployeeResourcePlannerValue value) { var dateAssignments = assignments.Where(x => (x.EmployeeID == employee.ID) && (x.Date >= from.Date && x.Date < to.Date)).ToArray(); if (dateAssignments.Length == 0) return false; value.IDs = assignments.Select(x => x.ID).ToArray(); value.Text = dateAssignments.Length == 1 ? (dateAssignments[0].ID != Guid.Empty ? (dateAssignments[0].JobNumber ?? "") : "XX") : $"{dateAssignments.Select(x => x.JobID).Distinct().Count()} jobs"; value.Assignments = dateAssignments; value.Color = Colors.LightGreen.ToString(); return true; } private static bool CheckRoster(EmployeeResourceModel employee, DateTime from, DateTime to, double standardHours, EmployeeResourcePlannerValue value) { value.Text = ""; var totalRostered = 0.0; for(var date = from; date < to; date = date.AddDays(1)) { var roster = RosterUtils.GetRoster(employee.Roster, employee.RosterStart, date); if(roster?.Enabled == true) { totalRostered += roster.Duration; } } var color1 = Colors.LightGray; var color2 = Colors.LightYellow; var percent = Math.Min(totalRostered / standardHours, 1.0); value.Foreground = new SolidColorBrush(ImageUtils.MixColors(color1, 1 - percent, color2)) { Opacity = 0.8 }; var brush = new LinearGradientBrush { Opacity = 0.8 }; brush.StartPoint = new Point(0,0); brush.GradientStops.Add(new GradientStop(Colors.LightYellow, 0.0)); brush.GradientStops.Add(new GradientStop(ImageUtils.MixColors(Colors.LightYellow, percent, Colors.LightGray), percent)); brush.GradientStops.Add(new GradientStop(Colors.LightGray, 1.0)); brush.EndPoint = new Point(1,0); value.Background = brush; return totalRostered.IsEffectivelyEqual(0.0); } private static EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves) { var standardleave = standardleaves.FirstOrDefault(x => (x.From <= curdate) && (x.To.Add(x.ToTime) > curdate) ); return (standardleave != null) ? new EmployeeResourcePlannerValue() { Text = standardleave.Code, Color = standardleave.Color} : null; } private static bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value) { if (leavevalue == null) return false; value.Text = leavevalue.Text; value.Color = leavevalue.Color; return true; } private bool CheckLeaveRequest(EmployeeResourceModel employee, DateTime from, DateTime to, LeaveRequestModel[] leaverequests, EmployeeResourcePlannerValue value) { var leaverequest = leaverequests.FirstOrDefault(c => (c.EmployeeID == employee.ID) && (c.From < to) && (c.To.Add(c.ToTime) >= from) && (Properties.IncludeUnApprovedLeave || c.Status == LeaveRequestStatus.Approved)); if (leaverequest == null) return false; value.Text = leaverequest.Code; value.Color = (leaverequest.Status == LeaveRequestStatus.Approved) ? leaverequest.Color : Colors.DimGray.ToString(); return true; } #region AutoGenerate Columns / Styling private class EmployeeResourcePlannerBackgroundConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is not EmployeeResourcePlannerValue val) return DependencyProperty.UnsetValue; return val.Background; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } private class EmployeeResourcePlannerForegroundConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is not EmployeeResourcePlannerValue val) return DependencyProperty.UnsetValue; return val.Foreground; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } private class EmployeeResourcePlannerFontStyleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is not EmployeeResourcePlannerValue val) return DependencyProperty.UnsetValue; return FontStyles.Normal; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } private class EmployeeResourcePlannerFontWeightConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is not EmployeeResourcePlannerValue val) return DependencyProperty.UnsetValue; return FontWeights.Normal; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } private class EmployeeResourcePlannerContentConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is not EmployeeResourcePlannerValue val) return DependencyProperty.UnsetValue; return val.Text; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } private void DataGrid_AutoGeneratingColumn(object? sender, AutoGeneratingColumnArgs e) { e.Column.TextAlignment = TextAlignment.Center; e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center; e.Column.ColumnSizer = GridLengthUnitType.None; var value = (e.Column.ValueBinding as Binding)!; if (value.Path.Path.Equals("Employee")) { e.Column.Width = 150; e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style; e.Column.AllowFocus = false; e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName + ".Name") }; } else if (value.Path.Path.Equals("Date")) { e.Column.Width = 80; e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style; e.Column.AllowFocus = false; } else { var style = new Style(typeof(GridCell)); style.Setters.Add(new Setter(BackgroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerBackgroundConverter() })); style.Setters.Add(new Setter(ForegroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerForegroundConverter() })); style.Setters.Add(new Setter(FontStyleProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontStyleConverter() })); style.Setters.Add(new Setter(FontWeightProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontWeightConverter() })); e.Column.CellStyle = style; e.Column.Width = 55; e.Column.HeaderStyle = Resources["ContentHeaderStyle"] as Style; if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns) { e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out var id) ? _employees.FirstOrDefault(x => x.ID == id)?.Name ?? value.Path.Path : value.Path.Path); } else { if(int.TryParse(value.Path.Path, out var idx)) { e.Column.HeaderText = _dates[idx].ToString("dd/MM/yyyy"); } } e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName), Converter = new EmployeeResourcePlannerContentConverter() }; //e.Column.ValueBinding = new Binding() { Path = new PropertyPath(e.Column.MappingName), Converter = new LeaveContentConverter() }; //e.Column.UseBindingValue = true; e.Column.AllowFocus = true; } } #endregion private bool HasData() { foreach (var cell in dataGrid.GetSelectedCells()) { if (!cell.IsDataRowCell) continue; var propertyCollection = dataGrid.View.GetPropertyAccessProvider(); var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName); if (cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0) return true; } return false; } private bool HasData(GridCellInfo cell) { if (!cell.IsDataRowCell) return false; var propertyCollection = dataGrid.View.GetPropertyAccessProvider(); var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName); return cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0; } private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e) { var vc = dataGrid.GetVisualContainer(); var p = Mouse.GetPosition(vc); var rci = vc.PointToCellRowColumnIndex(p); if (rci.RowIndex < 1 || rci.ColumnIndex < 1) { e.Handled = true; return; } dataGrid.ContextMenu.Items.Clear(); var bAssign = !HasData(dataGrid.CurrentCellInfo); var bClear = HasData(); if (bAssign) { foreach (var job in _jobs) { var assign = new MenuItem { Header = job.Name, Tag = job }; assign.Click += AssignJobClick; dataGrid.ContextMenu.Items.Add(assign); } } if (bClear && bAssign) dataGrid.ContextMenu.Items.Add(new Separator()); if (bClear) { var clear = new MenuItem { Header = "Clear Assignments" }; clear.Click += ClearJobClick; dataGrid.ContextMenu.Items.Add(clear); } } private void dataGrid_CellToolTipOpening(object sender, GridCellToolTipOpeningEventArgs e) { var record = (e.Record as DataRowView)?[e.Column.MappingName]; if (record is not EmployeeResourcePlannerValue value) return; if(value.IDs.Length > 0) { e.ToolTip.Template = TemplateGenerator.CreateControlTemplate( typeof(ToolTip), () => { var border = new Border { BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(0.75), CornerRadius = new CornerRadius(5), Background = new SolidColorBrush(Colors.LightYellow), Padding = new Thickness(5), }; var panel = new StackPanel(); foreach (var assignment in value.Assignments) { var textBlock = new TextBlock(); textBlock.Inlines.Add(new Run { Text = assignment.JobNumber, FontWeight = FontWeights.Bold }); textBlock.Inlines.Add(new Run { Text = $": {assignment.EffectiveStart():hh':'mm} - {assignment.EffectiveFinish():hh':'mm}" }); panel.Children.Add(textBlock); } border.Child = panel; return border; }); } } private void GetSelectionData(out DateTime from, out DateTime to, out Guid[] employees, out Guid[] assignments) { var emps = new List(); var items = new List(); from = DateTime.MaxValue; to = DateTime.MinValue; var period = GetPeriod(); foreach (var cell in dataGrid.GetSelectedCells()) { var row = (cell.RowData as DataRowView)!; var binding = (cell.Column.ValueBinding as Binding)!; DateTime date; if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns) { if (Guid.TryParse(binding.Path.Path, out var emp)) if (!emps.Contains(emp)) emps.Add(emp); date = (DateTime)row.Row.ItemArray.First()!; } else { if(int.TryParse(binding.Path.Path, out var idx)) { date = _dates[idx]; } else { date = DateTime.MinValue; } var empID = ((EmployeeResourceModel)row.Row.ItemArray.First()!).ID; if (!emps.Contains(empID)) emps.Add(empID); } if(date != DateTime.MinValue) { if (date < from) from = date; if (date + period > to) to = date + period; } foreach(var assignment in (row[binding.Path.Path] as EmployeeResourcePlannerValue)!.Assignments) { items.Add(assignment.ID); } } employees = emps.ToArray(); assignments = items.ToArray(); } private void AssignJobClick(object sender, RoutedEventArgs e) { if ((sender as MenuItem)?.Tag is not JobModel job) return; GetSelectionData(out var from, out var to, out var ids, out var assignments); var updates = new List(); foreach (var id in ids) { for (DateTime curdate = from; curdate < to; curdate = curdate.AddDays(1)) { var employee = _employees.FirstOrDefault(x => x.ID == id); if (employee != null) { bool bAvail = (GetStandardLeave(curdate, _standardleaves) == null) && !CheckLeaveRequest(employee, curdate, curdate.AddDays(1), _leaverequests, new EmployeeResourcePlannerValue()); var roster = bAvail ? RosterUtils.GetRoster(employee.Roster, employee.RosterStart, curdate) : null; if (roster?.Enabled == true && roster.Finish > roster.Start) { var assign = new Assignment(); assign.Date = curdate; assign.Booked.Start = roster.Start; assign.Booked.Finish = roster.Finish; assign.JobLink.ID = job.ID; assign.EmployeeLink.ID = id; assign.ActivityLink.ID = Properties.ActivityType; assign.JobScope.ID = job.DefaultScopeID; updates.Add(assign); } if (roster?.SplitShift == true && roster.Finish2 > roster.Start2) { var assign = new Assignment(); assign.Date = curdate; assign.Booked.Start = roster.Start2; assign.Booked.Finish = roster.Finish2; assign.JobLink.ID = job.ID; assign.EmployeeLink.ID = id; assign.ActivityLink.ID = Properties.ActivityType; assign.JobScope.ID = job.DefaultScopeID; updates.Add(assign); } } } } if (updates.Any()) { using (new WaitCursor()) { new Client().Save(updates, "Assigned from Employee Resource Planner"); Refresh(); } } } private void ClearJobClick(object sender, RoutedEventArgs e) { GetSelectionData(out DateTime from, out DateTime to, out Guid[] ids, out Guid[] assignments); if (assignments.Any() && MessageBox.Show("Clear Assignments?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { var deletes = assignments.Select(x => new Assignment() { ID = x }).ToArray(); using (new WaitCursor()) { new Client().Delete(deletes, "Deleted from Employee Resource Planner"); Refresh(); } } } public void Heartbeat(TimeSpan time) { } private void _employees_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args) { Properties.EmployeeSettings = args.Settings; DoSaveSettings(); } private void _employees_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args) { Properties.EmployeeSelection = args.Selection; DoSaveSettings(); Refresh(); } private void DateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (EventSuppressor.IsSet(Suppress.This)) return; Refresh(); } private void ViewType_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (EventSuppressor.IsSet(Suppress.This)) return; Properties.ViewType = (EmployeeResourcePlannerViewType)ViewType.SelectedValue; DoSaveSettings(); Refresh(); } private void LeaveType_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (EventSuppressor.IsSet(Suppress.This)) return; Properties.IncludeUnApprovedLeave = LeaveType.SelectedIndex > 0; DoSaveSettings(); Refresh(); } private void ActivityType_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (EventSuppressor.IsSet(Suppress.This)) return; Properties.ActivityType = (Guid)(ActivityType.SelectedValue ?? Guid.Empty); DoSaveSettings(); } private void JobFilter_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (EventSuppressor.IsSet(Suppress.This)) return; var sel = JobFilter.SelectedValue as CoreFilterDefinition; Properties.JobFilter = sel?.Name ?? ""; using (new WaitCursor()) { DoSaveSettings(); _jobs = new Client().Query( GetJobFilter(), JobModel.Columns, new SortOrder(x => x.JobNumber) ).Rows.Select(r => new JobModel(r)).ToArray(); } } private void JobFilterButton_Click(object sender, RoutedEventArgs e) { var window = new DynamicGridFilterEditor(_jobfilters, typeof(Job)); if (window.ShowDialog() == true) { new GlobalConfiguration("Job").Save(_jobfilters); JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter)); } } }