OpLock class

Lightweight, non-threadsafe locking mechanism to mutually lock methods from executing the same operation.

This class can be used when multiple operations in a GUI or single-threaded application are mutually exclusive. In contrast to the lock keyword of C#, concurrent calls are not serialised but entirely prevented. Instead of aborting the second call, you could implement any other behaviour, like interacting with the first running instance. Because no threadsafe locks are used, it uses less resources and is more performant. Additionally, the use of an OpFlag allows querying the current lock state.

Compatibility: .NET Version 2.0 or newer

Example

The following examples show how to use the OpLock and OpFlag classes. In the first example, two mutual TextBox updates are locked:

// Keeps the lock state of the text box
private OpFlag isUpdating = new OpFlag();
   
private void TextBox1_TextChanged(object sender, EventArgs e)
{
    // Evaluate the lock and abort if necessary
    if (isUpdating.IsSet) return;
    // Set the lock and perform the operation
    using (new OpLock(isUpdating))
    {
        // This causes the other event handler to be called, but it won’t do
        // anything because of the lock.
        TextBox2.Text = TextBox1.Text;
    }
}

private void TextBox2_TextChanged(object sender, EventArgs e)
{
    // Evaluate the lock and abort if necessary
    if (isUpdating.IsSet) return;
    // Set the lock and perform the operation
    using (new OpLock(isUpdating))
    {
        // This causes the other event handler to be called, but it won’t do
        // anything because of the lock.
        TextBox1.Text = TextBox2.Text;
    }
}

The second example shows a ViewModel class in which the opened editor window locks the import command:

// ViewModel class for the main window of the WPF application
class MainWindowViewModel : ViewModelBase
{
    // Reference to the editor window
    private EditorWindow editorView;
    // Keeps the editor lock state
    private OpFlag editorFlag = new OpFlag();
   
    // Commands for the application menu
    public DelegateCommand EditorCommand { get; private set; }
    public DelegateCommand ImportCommand { get; private set; }

    // ViewModel constructor
    public MainWindowViewModel()
    {
        // Initialise the commands
        EditorCommand = new DelegateCommand(OnEditorCommand);
        ImportCommand = new DelegateCommand(OnImportCommand, CanExecuteImport);

        // When the editor lock state changes, WPF must be informed that the
        // availability of the import command has changed.
        editorFlag.ValueChanged += (s, e) =>
        {
            ImportCommand.RaiseCanExecuteChanged();
        };
    }

    // Handles the editor command
    private void OnEditorCommand()
    {
        // If the lock is set, the editor window is already open. In that case it
        // just needs to be brought to the foreground. Otherwise it must be created
        // and opened.
        if (!editorFlag.IsSet)
        {
            // Create new editor window
            editorView = new EditorWindow();
            // Further initialisation...
           
            // Set the lock now
            editorFlag.Enter();
            // Free the lock when the window was closed
            editorView.Closed += (s, e) => { editorFlag.Leave(); };
            // Show the window, non-modal (the main window continues to be available)
            editorView.Show();
        }
        else
        {
            // Focus window
            editorView.Focus();
        }
    }

    // Tells whether the import command is currently available. That is always the
    // case when the editor window is not opened.
    private bool CanExecuteImport()
    {
        return !editorFlag.IsSet;
    }

    // Handles the import command
    private void OnImportCommand()
    {
        // ...
    }
}

Download

OpLock.cs2.4 KiBQuelltext der OpLock-Klasse

Licence and terms of use

Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. (GNU All-Permissive licence)

Statistic data

  • Created on 2012-08-06.