Show / Hide Table of Contents

KryptonOpenFileDialog

Overview

The KryptonOpenFileDialog class provides a Krypton-themed wrapper around the standard Windows file open dialog. It inherits from FileDialogWrapper (which inherits from ShellDialogWrapper) and implements IDisposable to provide enhanced appearance, consistent theming, and modern .NET functionality while maintaining full compatibility with the standard OpenFileDialog.

Class Hierarchy

System.Object
└── Krypton.Toolkit.ShellDialogWrapper (abstract)
    └── Krypton.Toolkit.FileDialogWrapper (abstract)
        └── Krypton.Toolkit.KryptonOpenFileDialog

Constructor and Initialization

public KryptonOpenFileDialog()

The constructor initializes:

  • Internal Dialog: Creates OpenFileDialog instance for native functionality
  • ShellDialogWrapper: Sets up Krypton theming and window management
  • Dispose Support: Implements proper resource cleanup

Key Properties

Multiselect Property

[DefaultValue(false)]
public bool Multiselect { get; set; }
  • Purpose: Controls whether multiple files can be selected simultaneously
  • Category: Behavior
  • Default Value: false
  • Affects: FileNames collection vs FileName string

Usage Example:

var dialog = new KryptonOpenFileDialog
{
    Multiselect = true,
    Title = "Select Multiple Images"
};

if (dialog.ShowDialog() == DialogResult.OK)
{
    foreach (string filename in dialog.FileNames)
    {
        ProcessImage(filename);
    }
}

ReadOnlyChecked Property

[DefaultValue(false)]
public bool ReadOnlyChecked { get; set; }
  • Purpose: Gets or sets whether the read-only check box is initially checked
  • Category: Behavior
  • Default Value: false
  • Note: Read-only checkbox is only shown when ShowReadOnly is enabled

Usage Example:

var dialog = new KryptonOpenFileDialog
{
    ReadOnlyChecked = true,
    Title = "Open Configuration File"
};

ShowReadOnly Property

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool ShowReadOnly { get; set; }

Important: This property throws InvalidConstraintException when accessed

  • Purpose: Intentionally disabled to maintain modern dialog experience
  • Reason: Windows 10+ doesn't support read-only checkbox in modern file dialogs
  • Alternative: Handle read-only checking in your application logic

SafeFileName Property

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string SafeFileName { get; }
  • Purpose: Gets the filename (without path) of the selected file
  • Returns: Filename only, safe from malicious paths
  • Usage: Safe for display or logging purposes

Usage Example:

if (dialog.ShowDialog() == DialogResult.OK)
{
    string safeName = dialog.SafeFileName;
    // SafeName = "document.txt" (no path information)
    Logger.Info($"User selected file: {safeName}");
}

SafeFileNames Property

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string[] SafeFileNames { get; }
  • Purpose: Gets filenames (without paths) of all selected files
  • Returns: Array of safe filenames only
  • Usage: Safe for display when Multiselect is enabled

Inherited FileDialogWrapper Properties

All standard file dialog properties are inherited and work identically:

File Path Properties

// File name selection
public override string FileName { get; set; }
public override string[] FileNames { get; }

// Initial directory
public override string InitialDirectory { get; set; }

// File extensions
public override string DefaultExt { get; set; }
public override string Filter { get; set; }
public override int FilterIndex { get; set; }

Behavior Properties

// File validation
public override bool CheckFileExists { get; set; }
public override bool CheckPathExists { get; set; }
public override bool ValidateNames { get; set; }

// Extension handling
public override bool AddExtension { get; set; }
public override bool SupportMultiDottedExtensions { get; set; }

// Link handling
public override bool DereferenceLinks { get; set; }

// Directory behavior
public override bool RestoreDirectory { get; set; }

Framework-Specific Properties (.NET 8.0+)

#if NET8_0_OR_GREATER
public override Guid? ClientGuid { get; set; }
#endif
  • Purpose: Associates GUID with dialog state for persistence
  • Availability: .NET 8.0 and later
  • Use Cases: Different dialog instances can have separate persisted states

Events and Collections

// File validation event
public override event CancelEventHandler? FileOk;

// Custom places for navigation
public override FileDialogCustomPlacesCollection CustomPlaces { get; }

File Opening Method

OpenFile Method

public Stream OpenFile()
  • Purpose: Opens the selected file with read-only permissions
  • Returns: Stream for reading the file
  • Exception: Throws ArgumentNullException if FileName is null
  • Usage: Convenient method for immediate file access

Usage Example:

var dialog = new KryptonOpenFileDialog
{
    Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*",
    FilterIndex = 1,
    CheckFileExists = true
};

if (dialog.ShowDialog() == DialogResult.OK)
{
    using (Stream fileStream = dialog.OpenFile())
    using (var reader = new StreamReader(fileStream))
    {
        string content = reader.ReadToEnd();
        ProcessFileContent(content);
    }
}

Dialog Behavior and Configuration

Standard File Open Properties

public void ConfigureDocumentOpen()
{
    var dialog = new KryptonOpenFileDialog
    {
        Title = "Open Document",
        InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
        Filter = "Word Documents (*.docx)|*.docx|Word 97-2003 (*.doc)|*.doc|All Files (*.*)|*.*",
        FilterIndex = 1,
        CheckFileExists = true,
        ValidateNames = true,
        AddExtension = true,
        RestoreDirectory = false
    };

    if (dialog.ShowDialog() == DialogResult.OK)
    {
        OpenDocument(dialog.FileName);
    }
}

Multi-File Selection

public void ImportMultipleImages()
{
    var dialog = new KryptonOpenFileDialog
    {
        Title = "Import Images",
        Multiselect = true,
        Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif|All Files|*.*",
        InitialDirectory = GetLastUsedImageFolder(),
        CheckFileExists = true
    };

    if (dialog.ShowDialog() == DialogResult.OK)
    {
        List<string> imageFiles = dialog.FileNames.ToList();
        ImportImageBatch(imageFiles);
    }
}

Safe File Operations

public class SafeFileOperations
{
    private static readonly string[] DangerousExtensions = { ".exe", ".bat", ".cmd", ".ps1" };
    
    public string? SelectDocument()
    {
        var dialog = new KryptonOpenFileDialog
        {
            Title = "Select Document",
            Filter = "Safe Documents (*.txt;*.docx;*.pdf)|*.txt;*.docx;*.pdf|All Files|*.*",
            CheckFileExists = true,
            ValidateNames = true
        };

        if (dialog.ShowDialog() == DialogResult.OK)
        {
            string filename = dialog.SafeFileName.ToLowerInvariant();
            
            if (DangerousExtensions.Any(ext => filename.EndsWith(ext)))
            {
                MessageBox.Show("This file type is not allowed.", "Security Warning", 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return null;
            }
            
            return dialog.FileName;
        }

        return null;
    }
}

Advanced Usage Patterns

File Type Validation

public class FileValidator
{
    public ValidationResult ValidateSelectedFile(KryptonOpenFileDialog dialog)
    {
        var result = new ValidationResult();

        // Check if file was actually selected
        if (string.IsNullOrEmpty(dialog.FileName))
        {
            result.AddError("No file selected");
            return result;
        }

        // File existence check
        if (dialog.CheckFileExists && !File.Exists(dialog.FileName))
        {
            result.AddError("Selected file does not exist");
            return result;
        }

        // Size validation
        var fileInfo = new FileInfo(dialog.FileName);
        if (fileInfo.Length > MaxAllowedFileSize)
        {
            result.AddError($"File too large: {fileInfo.Length:N0} bytes (max: {MaxAllowedFileSize:N0})");
            return result;
        }

        // Extension validation
        string allowedExtensions = dialog.Filter.Split('|')[dialog.FilterIndex * 2 - 2];
        var pattern = new Regex(allowedExtensions.Replace("*", ".*"));
        if (!pattern.IsMatch(dialog.FileName))
        {
            result.AddError("File extension not allowed");
            return result;
        }

        result.IsValid = true;
        return result;
    }
}

Dialog State Persistence

public class PersistentFileDialog : KryptonOpenFileDialog
{
    private static readonly string SettingsFile = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "MyApp", "DialogSettings.json");

    public PersistentFileDialog()
    {
        LoadSettings();
    }

    protected override void OnFileOk(CancelEventArgs e)
    {
        if (!e.Cancel)
        {
            SaveSettings();
        }
        base.OnFileOk(e);
    }

    private void LoadSettings()
    {
        try
        {
            if (File.Exists(SettingsFile))
            {
                var settings = JsonConvert.DeserializeObject<DialogSettings>(File.ReadAllText(SettingsFile));
                InitialDirectory = settings.LastDirectory;
                FilterIndex = settings.LastFilterIndex;
                Filter = settings.LastFilter;
            }
        }
        catch
        {
            // Use defaults
            InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        }
    }

    private void SaveSettings()
    {
        try
        {
            var settings = new DialogSettings
            {
                LastDirectory = Path.GetDirectoryName(FileName) ?? InitialDirectory,
                LastFilterIndex = FilterIndex,
                LastFilter = Filter
            };

            var directory = Path.GetDirectoryName(SettingsFile);
            Directory.CreateDirectory(directory!);
            File.WriteAllText(SettingsFile, JsonConvert.SerializeObject(settings, Formatting.Indented));
        }
        catch
        {
            // Ignore save errors
        }
    }
}

Multi-Selection with Validation

public class BatchFileProcessor
{
    public void ProcessBatch()
    {
        var dialog = new KryptonOpenFileDialog
        {
            Title = "Select Files for Processing",
            Multiselect = true,
            Filter = "Supported Files|*.txt;*.csv;*.json|All Files|*.*",
            CheckFileExists = true
        };

        if (dialog.ShowDialog() == DialogResult.OK)
        {
            var validFiles = ValidateFiles(dialog.FileNames);
            
            if (validFiles.Count != dialog.FileNames.Length)
            {
                var invalidFiles = dialog.FileNames.Except(validFiles).ToArray();
                ShowInvalidFilesWarning(invalidFiles);
            }

            if (validFiles.Any())
            {
                ProcessFilesAsync(validFiles);
            }
        }
    }

    private List<string> ValidateFiles(string[] files)
    {
        var validFiles = new List<string>();

        foreach (string file in files)
        {
            try
            {
                var fileInfo = new FileInfo(file);
                if (fileInfo.Exists && fileInfo.Length <= MaxFileSize && IsFileFormatSupported(file))
                {
                    validFiles.Add(file);
                }
            }
            catch
            {
                // Skip invalid files
            }
        }

        return validFiles;
    }
}

Custom Places Integration

public class FileDialogWithCustomPlaces : KryptonOpenFileDialog
{
    public FileDialogWithCustomPlaces()
    {
        InitializeCustomPlaces();
    }

    private void InitializeCustomPlaces()
    {
        // Add application-specific folders
        CustomPlaces.Add("My Documents", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
        CustomPlaces.Add("Desktop", Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
        
        // Add project folders
        CustomPlaces.Add("Documents", @"C:\MyApp\Documents");
        CustomPlaces.Add("Templates", @"C:\MyApp\Templates");
        CustomPlaces.Add("Backups", @"C:\MyApp\Backups");
        
        // Add network locations (if accessible)
        try
        {
            CustomPlaces.Add("Network Drive", @"\\Server\Shared");
        }
        catch
        {
            // Network location not accessible
        }
    }
}

Event Handling

FileOk Event Usage

public void ConfigureWithValidation()
{
    var dialog = new KryptonOpenFileDialog
    {
        Title = "Open Project File",
        Filter = "Project Files (*.proj)|*.proj|All Files|*.*",
        CheckFileExists = true
    };

    dialog.FileOk += (sender, e) =>
    {
        // Pre-validation before dialog closes
        if (!ValidateProjectFile(dialog.FileName))
        {
            e.Cancel = true;
            MessageBox.Show("Invalid project file format.", "Validation Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        else
        {
            LogFileSelection(dialog.SafeFileName);
        }
    };

    if (dialog.ShowDialog() == DialogResult.OK)
    {
        LoadProject(dialog.FileName);
    }
}

Design-Time Integration

Visual Studio Designer

  • Toolbox Integration: Available with custom bitmap representation
  • Property Window: All properties properly categorized and exposed
  • Custom Editors: Specialized editors for filter strings and custom places
  • Serialization: Design-time settings saved to designer files

Property Categories

  • Behavior: Dialog behavior (Multiselect, ReadOnlyChecked, file validation properties)
  • Data: File selection properties (FileName, FileNames, InitialDirectory)
  • Appearance: Visual customization (inherited from ShellDialogWrapper)

Performance Considerations

  • Memory Management: Proper disposal prevents memory leaks
  • File Enumeration: Large directories handled efficiently by Windows
  • Filter Performance: Complex filter patterns may slow file enumeration
  • Multi-Selection: Memory usage scales with number of selected files

Common Issues and Solutions

ShowReadOnly Access Errors

Issue: InvalidConstraintException when accessing ShowReadOnly
Solution: This is intended behavior; read-only functionality implemented in application layer

Multi-Selection Not Working

Issue: Only single file selection despite Multiselect = true
Solution: Ensure filters support multiple files or use "All Files" pattern

File Access Denied

Issue: File appears in dialog but cannot be opened
Solution: Implement proper exception handling around file operations:

try
{
    using (Stream stream = dialog.OpenFile())
    {
        // File operations
    }
}
catch (UnauthorizedAccessException)
{
    MessageBox.Show("Access denied to selected file.", "Error", 
        MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Filter Syntax Confusion

Issue: Filter not working as expected
Solution: Use proper filter syntax:

// Correct format
Filter = "Text Files (*.txt)|*.txt|Image Files (*.jpg;*.png)|*.jpg;*.png|All Files (*.*)|*.*";

// Format description: "Display Text|Pattern|Display Text|Pattern|..."

Migration from Standard OpenFileDialog

Direct Replacement

// Old code
using OpenFileDialog = System.Windows.Forms.OpenFileDialog;
var dialog = new OpenFileDialog();

// New code
var dialog = new KryptonOpenFileDialog();

Enhanced Features

// Standard OpenFileDialog (basic)
var standardDialog = new OpenFileDialog();

// KryptonOpenFileDialog (enhanced)
var kryptonDialog = new KryptonOpenFileDialog
{
    Title = "Enhanced File Selection",  // Custom title support
    Multiselect = true,                 // Multi-selection
    CheckFileExists = true,             // Validation
    ValidateNames = true               // Name validation
};

// Additional framework-specific features (.NET 8.0+)
#if NET8_0_OR_GREATER
kryptonDialog.ClientGuid = Guid.NewGuid();  // State persistence
#endif

Real-World Integration Examples

Project File Manager

public class ProjectManager
{
    public Project? OpenProject()
    {
        var dialog = new KryptonOpenFileDialog
        {
            Title = "Open Project",
            InitialDirectory = GetProjectsDirectory(),
            Filter = "Project Files (*.proj)|*.proj|All Files|*.*",
            CheckFileExists = true,
            ValidateNames = true
        };

        dialog.FileOk += OnProjectFileValidating;

        if (dialog.ShowDialog() == DialogResult.OK)
        {
            return LoadProjectFromFile(dialog.FileName);
        }

        return null;
    }

    private void OnProjectFileValidating(object? sender, CancelEventArgs e)
    {
        if (sender is KryptonOpenFileDialog dialog)
        {
            if (!IsValidProjectFile(dialog.FileName))
            {
                MessageBox.Show("Invalid project file format.", "Error", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                e.Cancel = true;
            }
        }
    }
}

Image Import Workflow

public class ImageImporter
{
    public List<string> ImportImages(bool multipleSelection = true)
    {
        var dialog = new KryptonOpenFileDialog
        {
            Title = multipleSelection ? "Import Images" : "Import Image",
            Multiselect = multipleSelection,
            Filter = "Image Files (*.jpg;*.jpeg;*.png;*.bmp;*.gif)|*.jpg;*.jpeg;*.png;*.bmp;*.gif|All Files|*.*",
            InitialDirectory = GetLastUsedImageDirectory(),
            CheckFileExists = true
        };

        if (dialog.ShowDialog() == DialogResult.OK)
       � {
            var selectedFiles = multipleSelection 
                ? dialog.FileNames.ToList() 
                : new List<string> { dialog.FileName };

            // Validate and filter images
            var validImages = selectedFiles.Where(IsValidImageFile).ToList();
            
            if (validImages.Count != selectedFiles.Count)
            {
                ShowImageValidationWarning(selectedFiles.Count - validImages.Count);
            }

            return validImages;
        }

        return new List<string>();
    }
}
Back to top Krypton Component Suite 2024 BSD 3-Clause License © Component Factory Pty Ltd, 2006 - 2016, All rights reserved. Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac, Tobitege, Lesarndro, KamaniAR & Ahmed Abdelhameed et al. 2017 - 2025. All rights reserved. https://github.com/Krypton-Suite