๐ฑ Screenbox Project Structure
May 16, 2026 ยท View on GitHub
This document provides a comprehensive overview of the Screenbox project's architecture, organization, and practical workflows for development.
๐ Table of Contents
- ๐ Overview
- ๐๏ธ Solution Structure
- ๐จ View Layer
- ๐ ViewModel Layer
- ๐ง Model Layer
- ๐๏ธ Architecture Rules
- ๐ ๏ธ Technology Stack
- ๐ Development Guidelines
๐ Overview
Screenbox is a modern media player for Windows built using the Universal Windows Platform (UWP) and LibVLCSharp. The application follows the Model-View-ViewModel (MVVM) design pattern with dependency injection for maintainable and testable code.
The architecture is built around clean separation of concerns:
- View Layer: XAML-based UI components and user controls
- ViewModel Layer: Presentation logic and data binding with MVVM
- Model Layer: Business logic, services, and media playback engine
๐๏ธ Solution Structure
The solution contains two main projects organized for clear separation of concerns:
Screenbox.sln
โโโ Screenbox/ # Main UWP application (UI layer)
โโโ Screenbox.Core/ # Core business logic library
Main Project: Screenbox
The primary UWP application containing all user interface components, platform-specific code, and XAML resources.
Core Library: Screenbox.Core
Contains the business logic, services, view models, and media playback components that can be shared across different platforms.
๐จ View Layer
The View layer is contained in the Screenbox project. This project consists primarily of XAML files and custom controls that define the user interface. App.xaml and the Styles folder contain resources referenced throughout the application, while the App.xaml.cs file serves as the main entry point and handles dependency injection configuration.
Core UI Structure
Screenbox uses a single-page application model with MainPage.xaml as the root container. The main page utilizes a NavigationView control for the navigation menu and houses content frames for different application modes:
MainPage.xaml (Root Container)
โโโ NavigationView (Menu System)
โโโ ContentFrame (Dynamic Content)
โโโ PlayerPage.xaml (Media Player Overlay)
Key Page Components
The application organizes its content into several main page categories:
HomePage.xaml: Recently accessed mediaVideosPage.xaml: Video library browsing with nested pages for categoriesMusicPage.xaml: Music library with artist, album, and song viewsNetworkPage.xaml: Network streaming and casting featuresPlayQueuePage.xaml: Current playlist and queue managementSettingsPage.xaml: Application configuration and preferences
Custom Controls Architecture
Screenbox implements numerous custom controls for specialized functionality:
Core Playback Controls
PlayerControls.xaml: Primary media control interfaceSeekBar.xaml: Timeline scrubbing and progress indicationVolumeControl.xaml: Audio level managementPlayerElement.xaml: Main video rendering surface
Media Display Controls
MediaListViewItem.xaml: Templated list items for media contentCommonGridViewItem.xaml: Grid layout for media thumbnailsPlaylistView.xaml: Specialized playlist display component
Dialogs and Overlay Controls
PropertiesDialog.xaml: Media file information displayOpenUrlDialog.xaml: Network URL input interface
Visual States
Visual States enable adaptive layouts that respond to window size changes, device orientation, and user interaction modes. Screenbox uses visual states extensively to create responsive experiences across different form factors.
Data Binding
Screenbox uses data binding extensively to create dynamic, responsive UI components. The application primarily uses the x:Bind markup extension for performance benefits over the legacy Binding syntax.
Example of x:Bind usage in media display:
<TextBlock Text="{x:Bind ViewModel.CurrentMedia.Title, Mode=OneWay}" />
<ProgressBar Value="{x:Bind ViewModel.PlaybackPosition, Mode=OneWay}" />
The binding system enables automatic UI updates when media state changes, providing smooth user experiences without manual UI manipulation code.
Navigation System
Navigation in Screenbox is handled through a custom NavigationService that maps ViewModels to their corresponding Pages. This system is configured in App.xaml.cs and enables loose coupling between the ViewModel and View layers:
new KeyValuePair<Type, Type>(typeof(HomePageViewModel), typeof(HomePage)),
new KeyValuePair<Type, Type>(typeof(VideosPageViewModel), typeof(VideosPage)),
new KeyValuePair<Type, Type>(typeof(MusicPageViewModel), typeof(MusicPage))
Localization System
Screenbox implements comprehensive multi-language support through the Windows and ReswPlus resource system, following UWP localization guidelines and ReswPlus guides for efficient localized resource management.
๐ ViewModel Layer
The ViewModel layer is contained in the Screenbox.Core project and serves as the intermediary between the UI components and business logic. ViewModels provide data sources for UI binding and encapsulate presentation logic while remaining independent of specific UI implementations.
Key ViewModel Architecture
Primary Application ViewModels
MainPageViewModel.cs: Root application state and navigation coordinationPlayerPageViewModel.cs: Media playback state and control logicPlayerControlsViewModel.cs: Playback control interactions and stateSettingsPageViewModel.cs: Application configuration management
Content Management ViewModels
MediaListViewModel.cs: Global playlist and media queue managementCommonViewModel.cs: Shared state across multiple pagesMediaViewModel.cs: Individual media item representationPlaylistViewModel.cs: Playlist-specific functionality
Library and Search ViewModels
HomePageViewModel.cs: Recent mediaVideosPageViewModel.cs: Video library browsingMusicPageViewModel.cs: Music library organizationSearchResultPageViewModel.cs: Search functionality and results
Observable Domain Entities
Some ViewModels โ specifically MediaViewModel, AlbumViewModel, and ArtistViewModel โ serve a dual role: they are MVVM observables and the effective domain entities for media items. This is a deliberate pragmatic choice for UWP MVVM: the application domain is inherently observable (tracks must notify when metadata loads, albums notify when thumbnails change), so the domain model and the observable layer naturally coincide.
As a result, these classes appear throughout the codebase in all layers โ including LibraryContext, PlaylistsContext, and SearchResult โ without violating the intended architecture. They should be thought of as observable domain entities rather than pure presentation objects, and should never contain XAML or UI framework references.
PropertyChanged Events
ViewModels implement property change notification through the CommunityToolkit.Mvvm framework. Most ViewModels inherit from ObservableObject or use source generators to implement INotifyPropertyChanged automatically:
[ObservableProperty]
private string _currentMediaTitle;
[ObservableProperty]
private TimeSpan _playbackPosition;
This enables automatic UI updates when ViewModel properties change, maintaining synchronization between the data layer and user interface.
Messaging System
Screenbox uses the CommunityToolkit.Mvvm messaging system for decoupled communication between components. This allows ViewModels, Services, and other components to communicate without direct references.
Core Message Types
Playback Control Messages
PlayMediaMessage.cs: Initiate media playbackTogglePlayPauseMessage.cs: Toggle playback stateChangeTimeRequestMessage.cs: Seek to specific time position
UI State Messages
PlayerControlsVisibilityChangedMessage.cs: Show/hide player controlsSettingsChangedMessage.cs: Application setting modificationsNavigationViewDisplayModeRequestMessage.cs: Navigation menu state changes
System Integration Messages
SuspendingMessage.cs: Application lifecycle eventsErrorMessage.cs: Error reporting and handlingNotificationRaisedEventArgs.cs: User notification display
๐ง Model Layer
The Model layer contains the core business logic and is primarily located in the Screenbox.Core project. This layer consists of services, media playback components, and data models that provide the foundation for the application functionality.
Services Architecture
Screenbox implements a comprehensive service-oriented architecture using Microsoft.Extensions.DependencyInjection for service registration and resolution. Services are registered in ServiceHelpers.cs and injected throughout the application.
Core Business Services
Media Management Services
IFilesService: File system operations and media discoveryILibraryService: Stateless operations for fetching and managing libraries.FetchMusicAsyncreturns aMusicLibraryand accepts an optionalIProgress<MusicLibrary>for incremental batch updates;FetchVideosAsyncworks analogously withVideosLibrary.ISearchService: Content search and filtering functionality
Playback and Streaming Services
IPlayerService: Media player initialization and playback item managementICastService: Stateless casting operations for renderer creation and configurationISystemMediaTransportControlsService: Windows media key integration
Persistence Services
ILastPositionTracker: Tracks and persists the last playback position for each media item, enabling resume-from-position functionality. Handles theSuspendingMessageto flush state to disk on app suspension.
System Integration Services
ISettingsService: Application configuration persistenceINotificationService: User notification managementIWindowService: Window management and display operations
Application Contexts
Contexts are observable application state holders shared across services and ViewModels. They represent the current runtime state of a domain area and act as the single source of truth for that state within the app.
Architectural rules for contexts:
- Written by: Services and coordinators (as a side effect of use-case execution)
- Read/observed by: ViewModels (via data binding and property-changed events)
- Must not: Call services or coordinators back (no circular dependencies)
- May contain: Messenger helper methods that broadcast state change events
Available contexts:
PlayerContext: Holds the currentIMediaPlayerinstance, allowing components to observe player state changesCastContext: Holds casting state including the active renderer watcher and selected rendererLibraryContext: Holds library state including theStorageLibraryhandles (MusicStorageLibrary,VideosStorageLibrary), loading flags, and the currentMusicLibraryandVideosLibrarycontainer objects. Written atomically byLibraryCoordinatorafter each fetch batch or on completion.PlaylistsContext: Holds the application-wide collection of user playlists
Stateful Coordinators
Some platform APIs (file system watchers, timers, device watchers) require stateful ownership to reliably subscribe/unsubscribe and to avoid duplicating watchers across views. Coordinators own these long-lived resources and orchestrate service calls in response to platform events.
Architectural rules for coordinators:
- Depend on: Services and contexts (never on ViewModels)
- Consumed by: ViewModels at initialization boundaries (to start lifecycle)
- Must expose: An interface (
ILibraryCoordinator, etc.) for testability - Implement:
IDisposableto clean up watchers/timers
Available coordinators:
LibraryCoordinator/ILibraryCoordinator: Stateful coordinator that owns libraryStorageFileQueryResultwatchers, debounce timers, and Xbox removable-storage device watchers. CallsILibraryService.FetchMusicAsync/FetchVideosAsyncwith anIProgress<T>handler that updatesLibraryContext.Music/LibraryContext.Videosincrementally as each batch arrives, then applies the final result on completion. This provides live UI progress updates during long library scans.
Helper Classes
Helper classes provide focused utilities and lightweight wrappers for specific functionality:
RendererWatcher: Lightweight wrapper around VLC's RendererDiscoverer for network renderer discovery, exposing events for renderer found/lost notifications and maintaining a list of available renderersDisplayRequestTracker: Manages display sleep prevention during media playback
Media Playback Engine
The media playback system is built on LibVLCSharp with custom abstractions for integration with the MVVM architecture:
Core Playback Components
IMediaPlayer: Media player abstraction interfaceVlcMediaPlayer.cs: VLC-based implementation of media playerPlaybackItem.cs: Media item wrapper with metadata and state
Track Management System
PlaybackAudioTrackList.cs: Audio track selection and switchingPlaybackVideoTrackList.cs: Video track and subtitle managementPlaybackSubtitleTrackList.cs: Subtitle track handlingPlaybackChapterList.cs: Chapter navigation support
The playback engine provides a clean interface for the ViewModel layer while abstracting the complexities of the underlying VLC media framework.
Data Models and Persistence
Media Information Models
MediaInfo.cs: Base media file informationVideoInfo.cs: Video-specific metadata and propertiesMusicInfo.cs: Audio metadata and music library information
Application State Models
MusicLibrary.cs: Immutable snapshot of the music library โSongs,Albums,Artists,UnknownAlbum, andUnknownArtist. Replaced by a new instance whenever the library is refreshed, so all relationships stay consistent. Has a staticEmptyinstance used as the initialLibraryContext.Musicvalue.VideosLibrary.cs: Immutable snapshot of the video library โVideoslist. Same replacement model asMusicLibrary.PersistentMediaRecord.cs: Saved playback state and resume positionsPersistentStorageLibrary.cs: Library folder persistence
๐๏ธ Architecture Rules
Dependency Flow
The following table summarizes the allowed dependency directions between layers:
| Layer | May depend on | Must not depend on |
|---|---|---|
| View (XAML + code-behind) | ViewModels, Contexts (read-only via DI) | Services, Coordinators directly |
| ViewModels | Services (via interface), Contexts, Factories | Coordinators (except at startup boundaries) |
| Contexts | Models, Playback abstractions | Services, Coordinators, ViewModels |
| Coordinators | Services (via interface), Contexts | ViewModels |
| Services | Other Services (via interface), Models, Playback | ViewModels, Contexts |
| Models / Playback | (no application dependencies) | All layers above |
DI and Factory Patterns
- All services and coordinators must be registered against their interface, not their concrete type.
- Use constructor injection exclusively. The service locator pattern (
Ioc.Default.GetRequiredService<T>()) is acceptable only in View code-behind for resolving ViewModels into pageDataContext. It must not be used inside ViewModels, Services, or Coordinators.
Stateless vs Stateful
- Stateless services (e.g.,
LibraryService,CastService): execute operations and return data to the caller. They do not own long-lived observable state, and must not read from or write to aContextdirectly. Results are returned as plain models (e.g.,MusicLibrary) and applied to the context by the coordinator. - Stateful coordinators (e.g.,
LibraryCoordinator): own watchers/timers and manage subscriptions/lifetimes. Register as singletons and implementIDisposable. - Stateful services (e.g.,
LastPositionTracker): own in-memory state but no platform subscriptions. Prefer a service interface; register as singletons.
๐ ๏ธ Technology Stack
- UWP (Universal Windows Platform): Windows application framework providing native performance and system integration
- C# 10.0: Primary programming language
- XAML: Declarative markup for user interface definition
- LibVLCSharp 3.7.0: Cross-platform media playback engine with extensive codec support
- CommunityToolkit.Mvvm: Modern MVVM framework with source generators and messaging
Development and Build Tools
- Visual Studio 2022: Primary integrated development environment
- MSBuild: Build system and project management
- XAML Styler: XAML formatting and style enforcement
Key Dependencies
MVVM and UI Framework
- Microsoft.UI.Xaml - WinUI controls and modern UI components
- CommunityToolkit.Mvvm - MVVM helpers, messaging, and source generators
- CommunityToolkit.Uwp - UWP community extensions
Dependency Injection
- Microsoft.Extensions.DependencyInjection - Service container and dependency injection
Media and Data Processing
- LibVLCSharp - VLC media player integration
- TagLibSharp - Audio metadata reading
- protobuf-net - Protocol Buffers serialization
Monitoring and Analytics
- Microsoft.AppCenter - Crash reporting and usage analytics
- Sentry - Error tracking and performance monitoring
๐ Development Guidelines
Code Organization
Follow C# coding conventions and UWP best practices throughout the codebase.
Naming Conventions
Adhere to .NET naming guidelines:
- PascalCase: Classes, methods, properties, public fields, enums
- camelCase: Local variables, parameters, private fields
- Interfaces: Prefixed with
I(e.g.,IMediaPlayer) - Private fields: Prefixed with
_(e.g.,_settingsService) - XAML resources: Descriptive, consistent naming patterns
File Organization
- One class per file
- Nested namespaces match folder structure
- Partial classes for XAML code-behind
Performance Considerations
Asynchronous Programming
- Use
async/awaitfor I/O operations following async best practices - Proper
ConfigureAwait(false)usage in library code - Task-based operations for file system access
Memory Management
- Follow .NET memory management guidelines
- Use weak references for event handlers where appropriate
UI Performance
- Follow UWP performance best practices
- Enable virtualization for large collections
- Implement proper image caching
- Process heavy operations on background threads
Build Configuration and Deployment
Supported Platforms
- x86: 32-bit Intel/AMD processors
- x64: 64-bit Intel/AMD processors
- ARM64: 64-bit ARM processors
Build Modes
- Debug: Development builds with debugging symbols
- Release: Optimized production builds
- StoreUpload: Microsoft Store submission packages
For detailed build configuration, see UWP packaging documentation.
External Resources and Documentation
Documentation
- UWP Developer Guide
- C# Programming Reference
- MVVM Toolkit Documentation
- Dependency Injection in .NET
Best Practices and Guidelines
This structure enables maintainable, scalable development while supporting the rich feature set of a modern media player application.