๐Ÿ“ฑ 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

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 media
  • VideosPage.xaml: Video library browsing with nested pages for categories
  • MusicPage.xaml: Music library with artist, album, and song views
  • NetworkPage.xaml: Network streaming and casting features
  • PlayQueuePage.xaml: Current playlist and queue management
  • SettingsPage.xaml: Application configuration and preferences

Custom Controls Architecture

Screenbox implements numerous custom controls for specialized functionality:

Core Playback Controls

  • PlayerControls.xaml: Primary media control interface
  • SeekBar.xaml: Timeline scrubbing and progress indication
  • VolumeControl.xaml: Audio level management
  • PlayerElement.xaml: Main video rendering surface

Media Display Controls

  • MediaListViewItem.xaml: Templated list items for media content
  • CommonGridViewItem.xaml: Grid layout for media thumbnails
  • PlaylistView.xaml: Specialized playlist display component

Dialogs and Overlay Controls

  • PropertiesDialog.xaml: Media file information display
  • OpenUrlDialog.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 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 coordination
  • PlayerPageViewModel.cs: Media playback state and control logic
  • PlayerControlsViewModel.cs: Playback control interactions and state
  • SettingsPageViewModel.cs: Application configuration management

Content Management ViewModels

  • MediaListViewModel.cs: Global playlist and media queue management
  • CommonViewModel.cs: Shared state across multiple pages
  • MediaViewModel.cs: Individual media item representation
  • PlaylistViewModel.cs: Playlist-specific functionality

Library and Search ViewModels

  • HomePageViewModel.cs: Recent media
  • VideosPageViewModel.cs: Video library browsing
  • MusicPageViewModel.cs: Music library organization
  • SearchResultPageViewModel.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 playback
  • TogglePlayPauseMessage.cs: Toggle playback state
  • ChangeTimeRequestMessage.cs: Seek to specific time position

UI State Messages

  • PlayerControlsVisibilityChangedMessage.cs: Show/hide player controls
  • SettingsChangedMessage.cs: Application setting modifications
  • NavigationViewDisplayModeRequestMessage.cs: Navigation menu state changes

System Integration Messages

  • SuspendingMessage.cs: Application lifecycle events
  • ErrorMessage.cs: Error reporting and handling
  • NotificationRaisedEventArgs.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 discovery
  • ILibraryService: Stateless operations for fetching and managing libraries. FetchMusicAsync returns a MusicLibrary and accepts an optional IProgress<MusicLibrary> for incremental batch updates; FetchVideosAsync works analogously with VideosLibrary.
  • ISearchService: Content search and filtering functionality

Playback and Streaming Services

  • IPlayerService: Media player initialization and playback item management
  • ICastService: Stateless casting operations for renderer creation and configuration
  • ISystemMediaTransportControlsService: Windows media key integration

Persistence Services

  • ILastPositionTracker: Tracks and persists the last playback position for each media item, enabling resume-from-position functionality. Handles the SuspendingMessage to flush state to disk on app suspension.

System Integration Services

  • ISettingsService: Application configuration persistence
  • INotificationService: User notification management
  • IWindowService: 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 current IMediaPlayer instance, allowing components to observe player state changes
  • CastContext: Holds casting state including the active renderer watcher and selected renderer
  • LibraryContext: Holds library state including the StorageLibrary handles (MusicStorageLibrary, VideosStorageLibrary), loading flags, and the current MusicLibrary and VideosLibrary container objects. Written atomically by LibraryCoordinator after 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: IDisposable to clean up watchers/timers

Available coordinators:

  • LibraryCoordinator / ILibraryCoordinator: Stateful coordinator that owns library StorageFileQueryResult watchers, debounce timers, and Xbox removable-storage device watchers. Calls ILibraryService.FetchMusicAsync / FetchVideosAsync with an IProgress<T> handler that updates LibraryContext.Music / LibraryContext.Videos incrementally 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 renderers
  • DisplayRequestTracker: 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 interface
  • VlcMediaPlayer.cs: VLC-based implementation of media player
  • PlaybackItem.cs: Media item wrapper with metadata and state

Track Management System

  • PlaybackAudioTrackList.cs: Audio track selection and switching
  • PlaybackVideoTrackList.cs: Video track and subtitle management
  • PlaybackSubtitleTrackList.cs: Subtitle track handling
  • PlaybackChapterList.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 information
  • VideoInfo.cs: Video-specific metadata and properties
  • MusicInfo.cs: Audio metadata and music library information

Application State Models

  • MusicLibrary.cs: Immutable snapshot of the music library โ€” Songs, Albums, Artists, UnknownAlbum, and UnknownArtist. Replaced by a new instance whenever the library is refreshed, so all relationships stay consistent. Has a static Empty instance used as the initial LibraryContext.Music value.
  • VideosLibrary.cs: Immutable snapshot of the video library โ€” Videos list. Same replacement model as MusicLibrary.
  • PersistentMediaRecord.cs: Saved playback state and resume positions
  • PersistentStorageLibrary.cs: Library folder persistence

๐Ÿ›๏ธ Architecture Rules

Dependency Flow

The following table summarizes the allowed dependency directions between layers:

LayerMay depend onMust not depend on
View (XAML + code-behind)ViewModels, Contexts (read-only via DI)Services, Coordinators directly
ViewModelsServices (via interface), Contexts, FactoriesCoordinators (except at startup boundaries)
ContextsModels, Playback abstractionsServices, Coordinators, ViewModels
CoordinatorsServices (via interface), ContextsViewModels
ServicesOther Services (via interface), Models, PlaybackViewModels, 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 page DataContext. 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 a Context directly. 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 implement IDisposable.
  • 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

Dependency Injection

Media and Data Processing

Monitoring and Analytics

๐Ÿ“‹ 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/await for I/O operations following async best practices
  • Proper ConfigureAwait(false) usage in library code
  • Task-based operations for file system access

Memory Management

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

Best Practices and Guidelines

This structure enables maintainable, scalable development while supporting the rich feature set of a modern media player application.