public ReactiveCadastroContratoViewModel(IReactiveRepository repository, DispatcherScheduler dispatcherScheduler)
            : base(repository, dispatcherScheduler)
        {
            // NOTE: Inicialização dos campos

            // Carrega os contratos do banco
            Repository.GetAll <Contrato>()
            .Busy(this)
            .Subscribe(contratos =>
            {
                foreach (var contrato in contratos)
                {
                    ContratosSalvos.Add(contrato);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega as naturalidades do banco de maneira assíncrona
            Repository.GetAll <Naturalidade>()
            .Busy(this)
            .Subscribe(naturalidades =>
            {
                foreach (var naturalidade in naturalidades)
                {
                    Naturalidades.Add(naturalidade);
                }
                NaturalidadeSelecionada = Naturalidades.First();
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            Repository.GetAll <EstadoCivil>()
            .Busy(this)
            .Subscribe(estadosCivis =>
            {
                foreach (var estadoCivil in estadosCivis)
                {
                    EstadosCivis.Add(estadoCivil);
                }
                EstadoCivilSelecionado = EstadosCivis.First();
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega os estados do banco de maneira assíncrona
            Repository.GetAll <Estado>()
            .Busy(this)
            .Subscribe(estados =>
            {
                foreach (var estado in estados)
                {
                    Estados.Add(estado);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega os bairros do banco de maneira assíncrona
            Repository.GetAll <Bairro>()
            .Busy(this)
            .Subscribe(bairros =>
            {
                foreach (var bairro in bairros)
                {
                    Bairros.Add(bairro);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega os cidades do banco de maneira assíncrona
            Repository.GetAll <Cidade>()
            .Busy(this)
            .Subscribe(cidades =>
            {
                foreach (var cidade in cidades)
                {
                    Cidades.Add(cidade);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega as secretarias do banco de maneira assíncrona
            Repository.GetAll <Secretaria>()
            .Busy(this)
            .Subscribe(secretarias =>
            {
                foreach (var secretaria in secretarias)
                {
                    Secretarias.Add(secretaria);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });

            // Carrega as jornadas do banco de maneira assíncrona
            Repository.GetAll <Jornada>()
            .Busy(this)
            .Subscribe(jornadas =>
            {
                foreach (var jornada in jornadas)
                {
                    Jornadas.Add(jornada);
                }
            },
                       ex =>
            {
                System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
            });


            // NOTE: Validação dos campos.
            // Para cada campo abaixo é criado um fluxo que verifica se o campo está preenchido. Caso não esteja
            // uma notificação de erro será propagada. O fluxo é acionado de maneira reativa, através da interação
            // do usuário na aplicação.

            var nomeHasErrors = this.WhenAnyValue(s => s.Nome, texto => string.IsNullOrEmpty(texto));

            ObservarErroCampoObrigatorio(nomeHasErrors, nameof(Nome));


            var cpfHasErros = this.WhenAnyValue(s => s.Cpf, texto => string.IsNullOrEmpty(texto));

            ObservarErroCampoObrigatorio(cpfHasErros, nameof(Cpf));


            var rgHasErros = this.WhenAnyValue(s => s.Rg, texto => string.IsNullOrEmpty(texto));

            ObservarErroCampoObrigatorio(rgHasErros, nameof(Rg));


            var orgExpHasErros = this.WhenAnyValue(s => s.OrgExp, texto => string.IsNullOrEmpty(texto));

            ObservarErroCampoObrigatorio(orgExpHasErros, nameof(OrgExp));


            var enderecoHasErros = this.WhenAnyValue(s => s.Endereco, texto => string.IsNullOrEmpty(texto));

            ObservarErroCampoObrigatorio(enderecoHasErros, nameof(Endereco));


            var estadoCivilHasErros = this.WhenAny(s => s.EstadoCivilSelecionado, e => e.Value is null);


            var naturalidadeHasErros = this.WhenAny(s => s.NaturalidadeSelecionada, e => e.Value is null);


            var estadoHasErros = this.WhenAny(s => s.EstadoSelecionado, e => e.Value is null);


            var bairroHasErros = this.WhenAny(s => s.BairroSelecionado, e => e.Value is null);


            var cidadeHasErros = this.WhenAny(s => s.CidadeSelecionada, e => e.Value is null);


            var secretariaHasErros = this.WhenAny(s => s.SecretariaSelecionada, e => e.Value is null);


            var orgaoHasErros = this.WhenAny(s => s.OrgaoSelecionado, e => e.Value is null);


            var deparmentoHasErros = this.WhenAny(s => s.DepartamentoSelecionado, e => e.Value is null);


            var dotacaoHasErros = this.WhenAny(s => s.DotacaoSelecionado, e => e.Value is null);


            var descricaoVinculoHasErros = this.WhenAny(s => s.DescricaoVinculoSelecionado, e => e.Value is null);


            var cargoHasErros = this.WhenAny(s => s.CargoSelecionado, e => e.Value is null);

            var jornadaHasErros = this.WhenAny(s => s.JornadaSelecionada, e => e.Value is null);


            // Criamos um fluxo que é a combinação de todos os fluxos de validação acima.
            // Caso algum fluxo apresente o valor verdadeiro, isto é, caso algum fluxo notifique uma mensagem de erro,
            // este fluxo irá propagar uma notificação que fará com que o comando abaixo não possa ser executado.

            var salvarCanExecute = Observable.CombineLatest(
                this.WhenAnyValue(s => s.IsBusy),
                nomeHasErrors,
                cpfHasErros,
                rgHasErros,
                orgExpHasErros,
                estadoCivilHasErros,
                naturalidadeHasErros,
                estadoHasErros,
                enderecoHasErros,
                bairroHasErros,
                cidadeHasErros,
                secretariaHasErros,
                orgaoHasErros,
                deparmentoHasErros,
                dotacaoHasErros,
                descricaoVinculoHasErros,
                cargoHasErros,
                jornadaHasErros)
                                   .Select(observables => !observables.Any(r => r == true));

            SalvarCommand = ReactiveCommand.Create(SalvarExecute, salvarCanExecute);



            // Regras de negócio

            // Ao selecionar uma nova secretaria carregamos dados referentes a esta secretaria
            this.WhenAnyValue(s => s.SecretariaSelecionada)
            .Subscribe(newSecretaria =>
            {
                if (newSecretaria != null)
                {
                    Repository.Get <DescricaoVinculo>(e => e.SecretariaId == newSecretaria.SecretariaId)
                    .Busy(this)
                    .Subscribe(descricaoVinculos =>
                    {
                        foreach (var descricaoVinculo in descricaoVinculos)
                        {
                            DescricaoVinculos.Add(descricaoVinculo);
                        }
                    },
                               ex =>
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
                    });

                    Repository.Get <Orgao>(e => e.SecretariaId == newSecretaria.SecretariaId)
                    .Busy(this)
                    .Subscribe(orgaos =>
                    {
                        foreach (var orgao in orgaos)
                        {
                            Orgaos.Add(orgao);
                        }
                    },
                               ex =>
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
                    });

                    Repository.Get <Departamento>(e => e.SecretariaId == newSecretaria.SecretariaId)
                    .Busy(this)
                    .Subscribe(departamentos =>
                    {
                        foreach (var departamento in departamentos)
                        {
                            Departamentos.Add(departamento);
                        }
                    },
                               ex =>
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
                    });

                    Repository.Get <Dotacao>(e => e.SecretariaId == newSecretaria.SecretariaId)
                    .Busy(this)
                    .Subscribe(dotacoes =>
                    {
                        foreach (var dotacao in dotacoes)
                        {
                            Dotacoes.Add(dotacao);
                        }
                    },
                               ex =>
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
                    });

                    Repository.Get <Cargo>(e => e.SecretariaId == newSecretaria.SecretariaId)
                    .Busy(this)
                    .Subscribe(cargos =>
                    {
                        foreach (var cargo in cargos)
                        {
                            Cargos.Add(cargo);
                        }
                    },
                               ex =>
                    {
                        System.Windows.Forms.MessageBox.Show(ex.Message, "Erro");
                    });
                }
            });
        }
        // Isso é um construtor, presente em qualquer linguagem de programação.
        // Todo o código escrito aqui será chamado SOMENTE UMA VEZ durante a inicialização da janela
        public CadastroContratoViewModel() : base(new Repository())
        {
            // Carregamos todos os Contratos gravados no banco de dados. isso é similar a um "SELECT * FROM Contrato";
            var contratos = Repository.GetAll <Contrato>();

            // Populamos o combobox com os contatos recuperados
            foreach (var contrato in contratos)
            {
                ContratosSalvos.Add(contrato);
            }

            // Carregamos todas as Naturalidades gravados no banco de dados. isso é similar a um "SELECT * FROM Naturalidade";
            var naturalidades = Repository.GetAll <Naturalidade>();

            // Populamos o combobox com as naturalidades recuperados
            foreach (var naturalidade in naturalidades)
            {
                Naturalidades.Add(naturalidade);
            }

            // Carregamos todas os estados civis gravados no banco de dados. isso é similar a um "SELECT * FROM EstadoCivil";
            var estadosCivis = Repository.GetAll <EstadoCivil>();

            // Populamos o combobox com os estadosCivis recuperados
            foreach (var estadoCivil in estadosCivis)
            {
                EstadosCivis.Add(estadoCivil);
            }
            // Aqui definimos que inicialmente o estado civil selecionado será o primeiro elemento do combobox
            EstadoCivilSelecionado = EstadosCivis.First();

            // Carregamos todas os Estados gravados no banco de dados. isso é similar a um "SELECT * FROM Estado";
            var estados = Repository.GetAll <Estado>();

            // Populamos o combobox com os estados recuperados
            foreach (var estado in estados)
            {
                Estados.Add(estado);
            }

            // Carregamos todas os Bairros gravados no banco de dados. isso é similar a um "SELECT * FROM Bairro";
            var bairros = Repository.GetAll <Bairro>();

            // Populamos o combobox com os bairros recuperados
            foreach (var bairro in bairros)
            {
                Bairros.Add(bairro);
            }

            // Carregamos todas as Cidades gravados no banco de dados. isso é similar a um "SELECT * FROM Cidade";
            var cidades = Repository.GetAll <Cidade>();

            // Populamos o combobox com as cidades recuperados
            foreach (var cidade in cidades)
            {
                Cidades.Add(cidade);
            }

            // Carregamos todas as Secretarias gravados no banco de dados. isso é similar a um "SELECT * FROM Secretaria";
            var secretarias = Repository.GetAll <Secretaria>();

            // Populamos o combobox com as secretarias recuperados
            foreach (var secretaria in secretarias)
            {
                Secretarias.Add(secretaria);
            }

            // Carregamos todas as Jornadas gravados no banco de dados. isso é similar a um "SELECT * FROM Jornada";
            var jornadas = Repository.GetAll <Jornada>();

            // Populamos o combobox com as jornadas recuperados
            foreach (var jornada in jornadas)
            {
                Jornadas.Add(jornada);
            }

            // Criamos um comando para o botão de Salvar. O método "SalvarExecute" será chamado sempre que o usuário acionar o botão
            SalvarCommand = new DelegateCommand(SalvarExecute);


            // Criamos uma rotina que será executada sempre que a secretaria selecionada mudar.
            // Diferente dos demais códigos escritos no construtor, esse código pode ser chamado mais de uma vez.
            this.WhenAnyValue(s => s.SecretariaSelecionada)
            .Subscribe(newSecretaria =>
            {
                // Atenção: O código de todo esse bloco será executado sempre que uma nova secretaria for selecionada.
                // "newSecretaria" representa a nova secretaria selecionada pelo usuário.


                // Caso a nova secretaria selecionada não seja null, isto é, não seja uma secretária inválida
                if (newSecretaria != null)
                {
                    // Carregamos todas as descrições associadas a nova secretaria selecionada. isso é similar a um "SELECT * FROM DescricaoVinculo WHERE SecretariaId = @newSecretariaId";
                    var descricaoVinculos = Repository.Get <DescricaoVinculo>(e => e.SecretariaId == newSecretaria.SecretariaId);
                    // Populamos o combobox com as descricaoVinculos recuperados
                    foreach (var descricaoVinculo in descricaoVinculos)
                    {
                        DescricaoVinculos.Add(descricaoVinculo);
                    }

                    // Carregamos todos os orgãos associados a nova secretaria selecionada. isso é similar a um "SELECT * FROM Orgao WHERE SecretariaId = @newSecretariaId";
                    var orgaos = Repository.Get <Orgao>(e => e.SecretariaId == newSecretaria.SecretariaId);
                    // Populamos o combobox com os orgaos recuperados
                    foreach (var orgao in orgaos)
                    {
                        Orgaos.Add(orgao);
                    }

                    // Carregamos todos os departamentos associados a nova secretaria selecionada. isso é similar a um "SELECT * FROM Departamento WHERE SecretariaId = @newSecretariaId";
                    var departamentos = Repository.Get <Departamento>(e => e.SecretariaId == newSecretaria.SecretariaId);
                    // Populamos o combobox com os departamentos recuperados
                    foreach (var departamento in departamentos)
                    {
                        Departamentos.Add(departamento);
                    }

                    // Carregamos todos as dotações associadas a nova secretaria selecionada. isso é similar a um "SELECT * FROM Dotacao WHERE SecretariaId = @newSecretariaId";
                    var dotacoes = Repository.Get <Dotacao>(e => e.SecretariaId == newSecretaria.SecretariaId);
                    // Populamos o combobox com os departamentos recuperados
                    foreach (var dotacao in dotacoes)
                    {
                        Dotacoes.Add(dotacao);
                    }

                    // Carregamos todos os Cargos associados a nova secretaria selecionada. isso é similar a um "SELECT * FROM Cargo WHERE SecretariaId = @newSecretariaId";
                    var cargos = Repository.Get <Cargo>(e => e.SecretariaId == newSecretaria.SecretariaId);
                    // Populamos o combobox com os cargos recuperados
                    foreach (var cargo in cargos)
                    {
                        Cargos.Add(cargo);
                    }
                }
            });
        }