Skip to main content
Commonmark migration
Source Link

###Purpose of the application**

Purpose of the application**

##Structure

Structure

###User controls

User controls

###Purpose of the application**

##Structure

###User controls

Purpose of the application**

Structure

User controls

Tweeted twitter.com/StackCodeReview/status/718584944650489856
deleted 520 characters in body; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Simple WPF application Uploading - potential extensibility problem due.dll files to number of propertiesa local computer

Purpose of the application

###Purpose of the application**

Structure

##Structure

User controls

###User controls

To keep things simpler and more reusable, I have created a user control for uploader section, as this will repeat three times - it has got:.

  • two path boxes (for paths of dll and xml files) - these are smaller usercontrols with browse/open selected file/display previous files functionalities
  • two upload buttons - one for dll and one for xml
  • two sets of two labels - to display modified date of local and server file for dll and xml files - labels can change colors
  • one 'open folder' button - to open server folder where dll file is
  • a fold/unfold button so that it could be collapsed
  • a checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

  • four dependency properties for paths (current path and list of previous paths for two types of files)
  • four dependency properties for labels
  • four dependency properties for label brushes
  • a couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
  • four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

  • four properties for paths, connected with application settings
  • four properties for xml file labels and brushes
  • four properties for dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

            #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
        private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
        public string CurrentWorkflowPluginConfigPath
        {
            get
            {
                return _currentWorkflowPluginConfigPath;
            }
            set
            {
                _currentWorkflowPluginConfigPath = value;
                Settings.Default.CurrentWorkflowPluginConfigPath = value;
                RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
                InitializeWorkflowPluginUploader();
            }
        }
    
        private bool _prevWorkflowConfigPathsEventSubscribed;
        private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
        public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
        {
            get
            {
                if (!_prevWorkflowConfigPathsEventSubscribed)
                {
                    _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                    _prevWorkflowConfigPathsEventSubscribed = true;
                }
                return _previousWorkflowPluginConfigPathsCollection;
            }
            set { }
        }
    
        void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
            Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
        }
        #endregion
    
    
    
           #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
        private string _localWorkflowPluginLastModified;
        public string LocalWorkflowPluginLastModified
        {
            get
            {
                return _localWorkflowPluginLastModified;
            }
            set
            {
                _localWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
    
        private string _serverWorkflowPluginLastModified;
        public string ServerWorkflowPluginLastModified
        {
            get
            {
                return _serverWorkflowPluginLastModified;
            }
            set
            {
                _serverWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
        private Brush _localWorkflowPluginLastModifiedBrush;
        public Brush LocalWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _localWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _localWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
            }
        }
    
    
        private Brush _serverWorkflowPluginLastModifiedBrush;
        public Brush ServerWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _serverWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _serverWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
            }
        }
    
        #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible? What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Thanks a lot for your feedback!

  • It has:

    • Two path boxes (for paths of .dll and XML files) - these are smaller usercontrols with browse/open selected file/display previous files' functionalities
    • Two upload buttons - one for .dll and one for XML
    • Two sets of two labels - to display modified date of local and server file for .dll and XML files - labels can change colors
    • One 'open folder' button - to open a server folder where a .dll file is
    • A fold/unfold button so that it could be collapsed
    • A checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

    • Four dependency properties for paths (current path and list of previous paths for two types of files)
    • Four dependency properties for labels
    • Four dependency properties for label brushes
    • A couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
    • Four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

    • Four properties for paths, connected with application settings
    • Four properties for XML file labels and brushes
    • Four properties for .dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

        #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
    private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
    public string CurrentWorkflowPluginConfigPath
    {
        get
        {
            return _currentWorkflowPluginConfigPath;
        }
        set
        {
            _currentWorkflowPluginConfigPath = value;
            Settings.Default.CurrentWorkflowPluginConfigPath = value;
            RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
            InitializeWorkflowPluginUploader();
        }
    }
    
    private bool _prevWorkflowConfigPathsEventSubscribed;
    private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
    public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
    {
        get
        {
            if (!_prevWorkflowConfigPathsEventSubscribed)
            {
                _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                _prevWorkflowConfigPathsEventSubscribed = true;
            }
            return _previousWorkflowPluginConfigPathsCollection;
        }
        set { }
    }
    
    void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
        Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
    }
    #endregion
    
    
    
       #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
    private string _localWorkflowPluginLastModified;
    public string LocalWorkflowPluginLastModified
    {
        get
        {
            return _localWorkflowPluginLastModified;
        }
        set
        {
            _localWorkflowPluginLastModified = value;
            RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
            Brush local;
            Brush server;
            ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
            LocalWorkflowPluginLastModifiedBrush = local;
            ServerWorkflowPluginLastModifiedBrush = server;
        }
    }
    
    
    private string _serverWorkflowPluginLastModified;
    public string ServerWorkflowPluginLastModified
    {
        get
        {
            return _serverWorkflowPluginLastModified;
        }
        set
        {
            _serverWorkflowPluginLastModified = value;
            RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
            Brush local;
            Brush server;
            ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
            LocalWorkflowPluginLastModifiedBrush = local;
            ServerWorkflowPluginLastModifiedBrush = server;
        }
    }
    
    private Brush _localWorkflowPluginLastModifiedBrush;
    public Brush LocalWorkflowPluginLastModifiedBrush
    {
        get
        {
            return _localWorkflowPluginLastModifiedBrush;
        }
        set
        {
            _localWorkflowPluginLastModifiedBrush = value;
            RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
        }
    }
    
    
    private Brush _serverWorkflowPluginLastModifiedBrush;
    public Brush ServerWorkflowPluginLastModifiedBrush
    {
        get
        {
            return _serverWorkflowPluginLastModifiedBrush;
        }
        set
        {
            _serverWorkflowPluginLastModifiedBrush = value;
            RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
        }
    }
    
    #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible. What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Simple WPF application - potential extensibility problem due to number of properties

    Purpose of the application

    Structure

    User controls

    To keep things simpler and more reusable, I have created a user control for uploader section, as this will repeat three times - it has got:

  • two path boxes (for paths of dll and xml files) - these are smaller usercontrols with browse/open selected file/display previous files functionalities
  • two upload buttons - one for dll and one for xml
  • two sets of two labels - to display modified date of local and server file for dll and xml files - labels can change colors
  • one 'open folder' button - to open server folder where dll file is
  • a fold/unfold button so that it could be collapsed
  • a checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

  • four dependency properties for paths (current path and list of previous paths for two types of files)
  • four dependency properties for labels
  • four dependency properties for label brushes
  • a couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
  • four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

  • four properties for paths, connected with application settings
  • four properties for xml file labels and brushes
  • four properties for dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

            #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
        private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
        public string CurrentWorkflowPluginConfigPath
        {
            get
            {
                return _currentWorkflowPluginConfigPath;
            }
            set
            {
                _currentWorkflowPluginConfigPath = value;
                Settings.Default.CurrentWorkflowPluginConfigPath = value;
                RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
                InitializeWorkflowPluginUploader();
            }
        }
    
        private bool _prevWorkflowConfigPathsEventSubscribed;
        private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
        public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
        {
            get
            {
                if (!_prevWorkflowConfigPathsEventSubscribed)
                {
                    _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                    _prevWorkflowConfigPathsEventSubscribed = true;
                }
                return _previousWorkflowPluginConfigPathsCollection;
            }
            set { }
        }
    
        void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
            Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
        }
        #endregion
    
    
    
           #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
        private string _localWorkflowPluginLastModified;
        public string LocalWorkflowPluginLastModified
        {
            get
            {
                return _localWorkflowPluginLastModified;
            }
            set
            {
                _localWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
    
        private string _serverWorkflowPluginLastModified;
        public string ServerWorkflowPluginLastModified
        {
            get
            {
                return _serverWorkflowPluginLastModified;
            }
            set
            {
                _serverWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
        private Brush _localWorkflowPluginLastModifiedBrush;
        public Brush LocalWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _localWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _localWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
            }
        }
    
    
        private Brush _serverWorkflowPluginLastModifiedBrush;
        public Brush ServerWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _serverWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _serverWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
            }
        }
    
        #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible? What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Thanks a lot for your feedback!

  • Uploading .dll files to a local computer

    ###Purpose of the application**

    ##Structure

    ###User controls

    To keep things simpler and more reusable, I have created a user control for uploader section, as this will repeat three times.

    It has:

    • Two path boxes (for paths of .dll and XML files) - these are smaller usercontrols with browse/open selected file/display previous files' functionalities
    • Two upload buttons - one for .dll and one for XML
    • Two sets of two labels - to display modified date of local and server file for .dll and XML files - labels can change colors
    • One 'open folder' button - to open a server folder where a .dll file is
    • A fold/unfold button so that it could be collapsed
    • A checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

    • Four dependency properties for paths (current path and list of previous paths for two types of files)
    • Four dependency properties for labels
    • Four dependency properties for label brushes
    • A couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
    • Four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

    • Four properties for paths, connected with application settings
    • Four properties for XML file labels and brushes
    • Four properties for .dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

        #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
    private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
    public string CurrentWorkflowPluginConfigPath
    {
        get
        {
            return _currentWorkflowPluginConfigPath;
        }
        set
        {
            _currentWorkflowPluginConfigPath = value;
            Settings.Default.CurrentWorkflowPluginConfigPath = value;
            RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
            InitializeWorkflowPluginUploader();
        }
    }
    
    private bool _prevWorkflowConfigPathsEventSubscribed;
    private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
    public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
    {
        get
        {
            if (!_prevWorkflowConfigPathsEventSubscribed)
            {
                _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                _prevWorkflowConfigPathsEventSubscribed = true;
            }
            return _previousWorkflowPluginConfigPathsCollection;
        }
        set { }
    }
    
    void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
        Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
    }
    #endregion
    
    
    
       #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
    private string _localWorkflowPluginLastModified;
    public string LocalWorkflowPluginLastModified
    {
        get
        {
            return _localWorkflowPluginLastModified;
        }
        set
        {
            _localWorkflowPluginLastModified = value;
            RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
            Brush local;
            Brush server;
            ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
            LocalWorkflowPluginLastModifiedBrush = local;
            ServerWorkflowPluginLastModifiedBrush = server;
        }
    }
    
    
    private string _serverWorkflowPluginLastModified;
    public string ServerWorkflowPluginLastModified
    {
        get
        {
            return _serverWorkflowPluginLastModified;
        }
        set
        {
            _serverWorkflowPluginLastModified = value;
            RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
            Brush local;
            Brush server;
            ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
            LocalWorkflowPluginLastModifiedBrush = local;
            ServerWorkflowPluginLastModifiedBrush = server;
        }
    }
    
    private Brush _localWorkflowPluginLastModifiedBrush;
    public Brush LocalWorkflowPluginLastModifiedBrush
    {
        get
        {
            return _localWorkflowPluginLastModifiedBrush;
        }
        set
        {
            _localWorkflowPluginLastModifiedBrush = value;
            RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
        }
    }
    
    
    private Brush _serverWorkflowPluginLastModifiedBrush;
    public Brush ServerWorkflowPluginLastModifiedBrush
    {
        get
        {
            return _serverWorkflowPluginLastModifiedBrush;
        }
        set
        {
            _serverWorkflowPluginLastModifiedBrush = value;
            RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
        }
    }
    
    #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible. What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    added 9952 characters in body
    Source Link
    Bartosz
    • 211
    • 2
    • 10
  • two path boxes (for paths of dll and xml files) - these are smaller usercontrols with browse/open selected file/display previous files functionalities
  • two upload buttons - one for dll and one for xml
  • two sets of two labels - to display modified date of local and server file for dll and xml files - labels can change colors
  • one 'open folder' button - to open server folder where dll file is
  • a fold/unfold button so that it could be collapsed
  • a checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

  • four dependency properties for paths (current path and list of previous paths for two types of files)
  • four dependency properties for labels
  • four dependency properties for label brushes
  • a couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
  • four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

  • four properties for paths, connected with application settings
  • four properties for xml file labels and brushes
  • four properties for dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

    dotnetfiddle sample here:

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

            #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
        private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
        public string CurrentWorkflowPluginConfigPath
        {
            get
            {
                return _currentWorkflowPluginConfigPath;
            }
            set
            {
                _currentWorkflowPluginConfigPath = value;
                Settings.Default.CurrentWorkflowPluginConfigPath = value;
                RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
                InitializeWorkflowPluginUploader();
            }
        }
    
        private bool _prevWorkflowConfigPathsEventSubscribed;
        private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
        public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
        {
            get
            {
                if (!_prevWorkflowConfigPathsEventSubscribed)
                {
                    _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                    _prevWorkflowConfigPathsEventSubscribed = true;
                }
                return _previousWorkflowPluginConfigPathsCollection;
            }
            set { }
        }
    
        void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
            Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
        }
        #endregion
    
    
    
           #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
        private string _localWorkflowPluginLastModified;
        public string LocalWorkflowPluginLastModified
        {
            get
            {
                return _localWorkflowPluginLastModified;
            }
            set
            {
                _localWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
    
        private string _serverWorkflowPluginLastModified;
        public string ServerWorkflowPluginLastModified
        {
            get
            {
                return _serverWorkflowPluginLastModified;
            }
            set
            {
                _serverWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
        private Brush _localWorkflowPluginLastModifiedBrush;
        public Brush LocalWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _localWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _localWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
            }
        }
    
    
        private Brush _serverWorkflowPluginLastModifiedBrush;
        public Brush ServerWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _serverWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _serverWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
            }
        }
    
        #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible? What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Thanks a lot for your feedback!

  • two path boxes (for paths of dll and xml files) - these are smaller usercontrols with browse/open selected file/display previous files functionalities
  • two upload buttons - one for dll and one for xml
  • two sets of two labels - to display modified date of local and server file for dll and xml files - labels can change colors
  • one 'open folder' button - to open server folder where dll file is
  • a fold/unfold button so that it could be collapsed
  • a checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

  • four dependency properties for paths (current path and list of previous paths for two types of files)
  • four dependency properties for labels
  • four dependency properties for label brushes
  • a couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
  • four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

  • four properties for paths, connected with application settings
  • four properties for xml file labels and brushes
  • four properties for dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

    dotnetfiddle sample here:

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible? What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Thanks a lot for your feedback!

  • two path boxes (for paths of dll and xml files) - these are smaller usercontrols with browse/open selected file/display previous files functionalities
  • two upload buttons - one for dll and one for xml
  • two sets of two labels - to display modified date of local and server file for dll and xml files - labels can change colors
  • one 'open folder' button - to open server folder where dll file is
  • a fold/unfold button so that it could be collapsed
  • a checkbox for autoupload

    enter image description here

    As a result, this user control has got 17 dependency properties and 4 events:

  • four dependency properties for paths (current path and list of previous paths for two types of files)
  • four dependency properties for labels
  • four dependency properties for label brushes
  • a couple of miscellaneous DPs for 'auto-uplad' checkbox, visibility, groupbox header etc
  • four routed events - for all buttons clicks

    Full XAML on dotnetfiddle, click on the View tab

    MainWindow.xaml

    Now, in my MainWindow.xaml file, apart from crap like status bar and menu bar, I need to define three UploaderControls. And this is where it starts being pretty monstrous (especially if I were to have e.g. 10 types of files to upload) For each of the controls I need a separate set of properties to be bound.

  • four properties for paths, connected with application settings
  • four properties for xml file labels and brushes
  • four properties for dll file labels and brushes

    Apart from that there's a bunch of miscellaneous props for visbility, auto-uplad and event handlers. I am not really concerned about those.

         <controls:UploaderControl ControlHeader="Workflow plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=WorkflowUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginPathsCollection}"
                                           CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentWorkflowPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousWorkflowPluginConfigPathsCollection}"
                                           DockPanel.Dock="Top"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=WorkflowAutoUpload,Mode=TwoWay}"
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginLastModifiedBrush}"
                                     LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalWorkflowPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalWorkflowConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerWorkflowPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerWorkflowConfigLastModifiedBrush}"
                                           UploadPluginClick="UploadButton_Click"
                                  UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Workflow}}" />
        <controls:UploaderControl ControlHeader="Archiver plugin"
                                  ContentVisibility="{Binding ElementName=ThisUc, Path=ArchiverUploaderVisibility}"
                                  HideButtonClick="OnHideButtonClick"
                                  CurrentProvidedConfigPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginConfigPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           PreviousConfigPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginConfigPathsCollection}"
                                           AutoUploadAfterBuild="{Binding ElementName=ThisUc,Path=ArchiverAutoUpload, Mode=TwoWay}"
                                           CurrentProvidedPath="{Binding ElementName=ThisUc, Path=CurrentArchiverPluginPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                           OpenServerFolder="UploaderControl_OnOpenServerFolder"
                                           DockPanel.Dock="Top"
                                           PreviousPathsCollection="{Binding ElementName=ThisUc, Path=PreviousArchiverPluginPathsCollection}"
                                          
                                           LocalLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModified}"
                                           LocalLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverPluginLastModifiedBrush}"
                                           ServerLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModified}"
                                           ServerLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverPluginLastModifiedBrush}"
                                           
                                           LocalConfigLastModified="{Binding ElementName=ThisUc, Path=LocalArchiverPluginConfigLastModified}"
                                           LocalConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=LocalArchiverConfigLastModifiedBrush}"
                                           ServerConfigLastModified="{Binding ElementName=ThisUc, Path=ServerArchiverPluginConfigLastModified}"
                                           ServerConfigLastModifiedBrush="{Binding ElementName=ThisUc, Path=ServerArchiverConfigLastModifiedBrush}"
                                           
                                            UploadPluginClick="UploadButton_Click"
                                            UploadConfigClick="UploaderControl_OnUploadConfigClick"
                                           UploaderName="{Binding Source={x:Static tmsObjectsNames:TmsServiceNames.Archiver}}" />
    

    C#

    For all the dependency properties above I have separate properties that are almost identical, except they are for different uploader type (workflow, archive, processing). Do I really need it like that? I suppose not, but I don't know how to handle this better.

    Sample properties

            #region Wokrlfow plugin ConfigPathBox //this one will be 'repeated' six times - 3x for different file types and 2x for dll and xml
    
    
        private string _currentWorkflowPluginConfigPath = Settings.Default.CurrentWorkflowPluginConfigPath;
        public string CurrentWorkflowPluginConfigPath
        {
            get
            {
                return _currentWorkflowPluginConfigPath;
            }
            set
            {
                _currentWorkflowPluginConfigPath = value;
                Settings.Default.CurrentWorkflowPluginConfigPath = value;
                RaisePropertyChanged(nameof(CurrentWorkflowPluginConfigPath));
                InitializeWorkflowPluginUploader();
            }
        }
    
        private bool _prevWorkflowConfigPathsEventSubscribed;
        private ObservableCollection<string> _previousWorkflowPluginConfigPathsCollection = Settings.Default.PreviousWorkflowPluginConfigPathsCollection ?? new ObservableCollection<string>();
        public ObservableCollection<string> PreviousWorkflowPluginConfigPathsCollection
        {
            get
            {
                if (!_prevWorkflowConfigPathsEventSubscribed)
                {
                    _previousWorkflowPluginConfigPathsCollection.CollectionChanged += _previousWorkflowConfigPathsList_CollectionChanged;
                    _prevWorkflowConfigPathsEventSubscribed = true;
                }
                return _previousWorkflowPluginConfigPathsCollection;
            }
            set { }
        }
    
        void _previousWorkflowConfigPathsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            RaisePropertyChanged(nameof(PreviousWorkflowPluginConfigPathsCollection));
            Settings.Default.PreviousWorkflowPluginConfigPathsCollection = PreviousWorkflowPluginConfigPathsCollection;
        }
        #endregion
    
    
    
           #region Workflow // this is a section for last modified info along with brushes for coloring. Again, these will be 'repeated' six times.
    
        private string _localWorkflowPluginLastModified;
        public string LocalWorkflowPluginLastModified
        {
            get
            {
                return _localWorkflowPluginLastModified;
            }
            set
            {
                _localWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
    
        private string _serverWorkflowPluginLastModified;
        public string ServerWorkflowPluginLastModified
        {
            get
            {
                return _serverWorkflowPluginLastModified;
            }
            set
            {
                _serverWorkflowPluginLastModified = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModified));
                Brush local;
                Brush server;
                ColorizeLabels(LocalWorkflowPluginLastModified, out local, ServerWorkflowPluginLastModified, out server);
                LocalWorkflowPluginLastModifiedBrush = local;
                ServerWorkflowPluginLastModifiedBrush = server;
            }
        }
    
        private Brush _localWorkflowPluginLastModifiedBrush;
        public Brush LocalWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _localWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _localWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(LocalWorkflowPluginLastModifiedBrush));
            }
        }
    
    
        private Brush _serverWorkflowPluginLastModifiedBrush;
        public Brush ServerWorkflowPluginLastModifiedBrush
        {
            get
            {
                return _serverWorkflowPluginLastModifiedBrush;
            }
            set
            {
                _serverWorkflowPluginLastModifiedBrush = value;
                RaisePropertyChanged(nameof(ServerWorkflowPluginLastModifiedBrush));
            }
        }
    
        #endregion
    

    I think I am handling button click events pretty well with switches, so that all uploaders point to the same handler and then proper object is launched:

     private async void UploaderControl_OnUploadConfigClick(object sender, RoutedEventArgs e)
            {
                FileUploadInfo = "Preparing upload...";
                Application.Current.MainWindow.Cursor = Cursors.Wait;
    
                string pluginName = (sender as Controls.UploaderControl).UploaderName;
                switch (pluginName)
                {
                    case TmsServiceNames.Workflow:
                        await WorkflowFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.Archiver:
                        await ArchiverFileUploader?.UploadConfig(false);
                        break;
                    case TmsServiceNames.PptService:
                        await PptFileUploader?.UploadConfig(false);
                        break;
                }
                Application.Current.MainWindow.Cursor = Cursors.Arrow;
            }
    

    I have a big problem with initialization of each of the FileUploader classes. For each of the three types I had to create a separate method:

     private void InitializeWorkflowPluginUploader()
            {
                if (CurrentWorkflowPluginPath.IsExistingFilePath() && ServicesManager.Services.ContainsKey(TmsServiceNames.Workflow))
                {
                    IProgress<FileWatcherProgress> p = new Progress<FileWatcherProgress>(x =>
                    {
                        LocalWorkflowPluginLastModified = x.LocalFileVersion ?? LocalWorkflowPluginLastModified;
                        ServerWorkflowPluginLastModified = x.ServerFileVersion ?? ServerWorkflowPluginLastModified;
                        LocalWorkflowPluginConfigLastModified = x.LocalConfigFileVersion ?? LocalWorkflowPluginConfigLastModified;
                        ServerWorkflowPluginConfigLastModified = x.ServerConfigFileVersion ?? ServerWorkflowPluginConfigLastModified;
                        FileUploadInfo = x.OverallInfo ?? FileUploadInfo;
                        if (x.PopupText != null)
                        {
                            LaunchUploaderPopup(x.PopupTitle, x.PopupText);
                        }
                    });
                    WorkflowFileUploader = new RemoteFileUploader(CurrentWorkflowPluginPath, CurrentWorkflowPluginConfigPath, new TmsFolderPaths().Workflow, WorkflowAutoUpload, ShowPopupAfterAutoUpload, ServicesManager.Services[TmsServiceNames.Workflow], p);
                }
            }
    

    I would like to create all these in a single method, where I could pass a bunch of properties as parameters - in this case for example file paths and properties for status labels (LocalWorkflowPluginLastModified) etc, which are different for each file type.

    So, summing up, while this is finished and will not grow any further, I would like to do a better structure next time, reduce the number of properties if possible? What would I do if I had to add 5 more file types, and then add 2 more labels to each of them?

    Thanks a lot for your feedback!

  • Source Link
    Bartosz
    • 211
    • 2
    • 10
    Loading