{"id":31703945,"url":"https://github.com/tirsvadgui/dotnet.wpf.template","last_synced_at":"2026-02-14T21:02:15.284Z","repository":{"id":315510644,"uuid":"1059805802","full_name":"TirsvadGUI/Dotnet.Wpf.Template","owner":"TirsvadGUI","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-19T06:31:53.000Z","size":536,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-08T22:47:04.644Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TirsvadGUI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-19T01:20:13.000Z","updated_at":"2025-09-19T06:31:57.000Z","dependencies_parsed_at":"2025-09-19T03:31:18.254Z","dependency_job_id":"434f39e0-9489-4878-af09-0819a5a502e9","html_url":"https://github.com/TirsvadGUI/Dotnet.Wpf.Template","commit_stats":null,"previous_names":["tirsvadgui/dotnet.wpf.template"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TirsvadGUI/Dotnet.Wpf.Template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TirsvadGUI%2FDotnet.Wpf.Template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TirsvadGUI%2FDotnet.Wpf.Template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TirsvadGUI%2FDotnet.Wpf.Template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TirsvadGUI%2FDotnet.Wpf.Template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TirsvadGUI","download_url":"https://codeload.github.com/TirsvadGUI/Dotnet.Wpf.Template/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TirsvadGUI%2FDotnet.Wpf.Template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29455601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T15:52:44.973Z","status":"ssl_error","status_checked_at":"2026-02-14T15:52:11.208Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-08T22:46:51.195Z","updated_at":"2026-02-14T21:02:15.274Z","avatar_url":"https://github.com/TirsvadGUI.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿﻿[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n[![License][license-shield]][license-url]\n[![LinkedIn][linkedin-shield]][linkedin-url]\n\n# ![Logo][logo] Dotnet.Wpf.Template\n\nA clean WPF (.NET 9) starter focused on:\n- Separation of concerns\n- Dark and light themes\n- Dependency Injection (DI)\n- Connection strings saved encrypted. Auto popup for first time run or missing configuration.\n\n## Table of Contents\n- [About the project](#about-the-project)\n- [Goals](#goals)\n- [Prerequisites](#prerequisites)\n- [Features](#features)\n- [Quick start](#quick-start)\n- [Project structure (suggested)](#project-structure-suggested)\n- [Notes](#notes)\n- [License](#license)\n- [Contact](#contact)\n- [Acknowledgements](#acknowledgements)\n- [Contributing](#contributing)\n\n## About the project\nThis project is a template for building WPF applications using .NET 9.\nIt incorporates best practices such as the MVVM pattern, dependency injection, and theme management. The template is designed to help developers get started quickly while maintaining a clean and organized codebase.\n\n## Goals\n- Provide a solid foundation for building WPF applications\n- Promote best practices in software architecture\n- Enable easy customization and extension\n\n## Prerequisites\n- [.NET 9 SDK](https://dotnet.microsoft.com/download/dotnet/9.0)\n- Visual Studio, Visual Studio Code or other C# ide with WPF support\n\n## Features\n- WPF (.NET 9)\n- MVVM pattern\n- Dependency Injection (DI) with Microsoft.Extensions.DependencyInjection\n- Light and dark themes with easy switching\n- Connection string saved encrypted in user AppData folder\n- Popup windows for first time run or missing configuration\n- Project structure keeping UI, domain, and infrastructure clearly separated\n\n## Quick start\n### 1. Clone and open in Visual Studio 2022.  \n`git clone https://github.com/TirsvadGUI/Dotnet.Wpf.Template.git`\n\n## Project structure (suggested)\nLegend for levels and items:\n- 🗂️ Level 1: repository root\n- 📁 Level 2: top-level folder\n- 📂 Level 3: subfolder\n- 🗃️ Level 4+: deeper subfolders\n- 🧩 Project (csproj)\n- 📄 File\n- 🎨 Theme resources\n- ⚙️ Configuration\n- 🧪 Tests\n\n```text\n🗂️ Dotnet.Wpf.Template\n├─ 📁 src\n│  ├─ 🧩 Template.App (WPF UI)\n│  │  ├─ 📂 Configuration (Popup windows for first time run or missing configuration)\n│  │  ├─ 📂 Views (MVVM)\n│  │  ├─ 📂 ViewModels (MVVM)\n│  │  ├─ 🎨 Themes\n│  │  │  ├─ 📄 Theme.Light.xaml\n│  │  │  └─ 📄 Theme.Dark.xaml\n│  │  ├─ 📂 Resources (styles, converters, controls)\n│  │  ├─ 📄 appsettings.json (optional, not for secrets)\n│  │  ├─ 📄 appsettings.Development.json (optional, not for secrets)\n│  │  ├─ 📄 App.xaml \n│  │  └─ 📄 App.xaml.cs (application bootstrap - Generic Host + DI)\n│  ├─ 🧩 Template.Infrastructure (integrations)\n│  │  ├─ 📂 Configuration (Read / Save Connection string)\n│  │  ├─ 📂 Data (clients, context, mappers)\n│  │  ├─ 📂 Repositories (data access)\n│  │  ├─ 📂 Services (APIs, email, logging)\n│  │  └─ 📄 DependencyInjection.cs\n│  ├─ 🧩 Template.Application (use cases)\n│  │  ├─ 📂 Abstractions (interfaces)\n│  │  ├─ 📂 DTOs (data transfer objects)\n│  │  ├─ 📂 Services (business logic)\n│  │  └─ 📄 DependencyInjection.cs\n│  └─ 🧩 Template.Domain (core models)\n│     ├─ 📂 Models\n│     └─ 📂 Abstractions (interfaces)\n├─ 🧪 tests (optional)\n│  └─ 🧩 Template.App.Tests\n├─ 📄 README.md\n└─ 📄 LICENSE.txt\n```\n\n- `App.xaml`, `App.xaml.cs` – application bootstrap (Generic Host + DI)\n- `Views/`, `ViewModels/` – presentation (MVVM)\n- `Infrastructure/` – external services (data access, APIs)\n- `Themes/Theme.Light.xaml`, `Themes/Theme.Dark.xaml` – theme resources\n- `appsettings.json` (optional, not for secrets)\n- User secrets or environment variables for secrets\n\nThis keeps UI, domain, and infrastructure clearly separated.\n\n## How it works\n\n### Dependency Injection (DI)\nIn `App.xaml.cs` we build a Host and register services\n- DI constructs `MainWindow` and can inject dependencies (like `MainViewModel`) into its constructor.\n\n### MVVM in a nutshell\n- View (`MainWindow.xaml`): defines the UI in XAML.\n- ViewModel (`MainViewModel`): holds the data and commands (no UI code).\n- Binding connects them (e.g., `{Binding Title}` displays a `Title` property from the ViewModel).\n\nThis keeps UI and logic separate and testable.\n\n### Connection string flow\n`Template.Infrastructure.Configuration.EncryptedConnectionStringProvider` tries:\n1. Configuration (appsettings, env vars, or User Secrets)\n2. Encrypted store (saved from a previous run)\n3. UI prompt (popup) if still missing\n\nIf the popup is used and you click OK, it saves the encrypted connection string so you don’t have to enter it again.\n\n### Themes (Light/Dark)\nTo use a theme, merge it in `App.xaml`:\n```xml\n\u003cApplication ...\u003e\n    \u003cApplication.Resources\u003e\n        \u003cResourceDictionary\u003e\n            \u003cResourceDictionary.MergedDictionaries\u003e\n                \u003c!-- Pick one --\u003e\n                    \u003cResourceDictionary Source=\"Themes/Theme.Light.xaml\" /\u003e \n                \u003c!-- or --\u003e \n                    \u003c!-- \u003cResourceDictionary Source=\"Themes/Theme.Dark.xaml\" /\u003e --\u003e \n            \u003c/ResourceDictionary.MergedDictionaries\u003e \n        \u003c/ResourceDictionary\u003e \n    \u003c/Application.Resources\u003e \n\u003c/Application\u003e\n```\n\n## Notes\n- Separation of concerns: keep UI (Views), state/logic (ViewModels), core logic (Domain), and integrations (Infrastructure) decoupled and wired via DI.\n- Keep secrets out of source control; prefer environment variables or User Secrets.\n\n## Common tasks\n- Change window title: open `MainWindow.xaml` and set `Title=\"Your App\"`.\n- Add a service: register it in `App.xaml.cs` via `services.AddSingleton\u003cIMyService, MyService\u003e();`, then inject into constructors.\n- Add a new View + ViewModel: create files in `Views/` and `ViewModels/`, register the View in DI if you want to resolve it from the container.\n\n\n## License\n\n\n## Contact\n- Issues: [GitHub Issues][issues-url]\n- LinkedIn: [Profile][linkedin-url]\n\n## Acknowledgements\n- .NET team and WPF community\n- MVVM patterns and resources shared by the community\n\n## Contributing\nContributions are welcome!  \n- Fork the repo\n- Create a feature branch\n- Commit changes\n- Open a Pull Request\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n[contributors-shield]: https://img.shields.io/github/contributors/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[contributors-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[forks-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/network/members\n[stars-shield]: https://img.shields.io/github/stars/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[stars-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/stargazers\n[issues-shield]: https://img.shields.io/github/issues/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[issues-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/issues\n[license-shield]: https://img.shields.io/github/license/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[license-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/blob/master/LICENSE.txt\n[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge\u0026logo=linkedin\u0026colorB=555\n[linkedin-url]: https://www.linkedin.com/in/jens-TirsvadGUI-nielsen-13b795b9/\n[githubIssue-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template/issues/\n[repo-size-shield]: https://img.shields.io/github/repo-size/TirsvadGUI/Dotnet.Wpf.Template?style=for-the-badge\n[repo-url]: https://github.com/TirsvadGUI/Dotnet.Wpf.Template.git\n\n[logo]: https://raw.githubusercontent.com/TirsvadGUI/Dotnet.Wpf.Template/master/images/logo/32x32/logo.png","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftirsvadgui%2Fdotnet.wpf.template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftirsvadgui%2Fdotnet.wpf.template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftirsvadgui%2Fdotnet.wpf.template/lists"}