I have a my SQLiteOpenHelper class, which is written as a singleton. I should note that I am not doing this in Java, I am using Xamarin.Android C# to write this.
Here's a snippet from that class:
public class DatabaseHelper : SQLiteOpenHelper
{
private static readonly string TAG = typeof(DatabaseHelper).FullName;
private static readonly string _databaseName = "istockdb";
private static readonly int _databaseVersion = 32;
private static DatabaseHelper _instance;
private Context _context;
private DatabaseHelper(Context context) : base(context, _databaseName, null, _databaseVersion)
{
_context = context;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static DatabaseHelper Instance(Context context)
{
// *** Use the application context, which will ensure that ***
// *** the Activity's context is not accidentally leaked ***
return _instance ?? (_instance = new DatabaseHelper(context.ApplicationContext));
}
}
So I have my DatabaseHelper that is a singleton and is used like this within Activities and Services:
Service:
[Service(Name=Text.MobileBackgroundHbService, Enabled = true, Exported = true), IntentFilter(new []{Intents.SyncHeartbeats})]
public class BGHeartbeatService : BaseIntentService
{
public BGHeartbeatService()
{
this._database = DatabaseHelper.Instance(Application.Context);
}
protected override void OnHandleIntent(Intent intent)
{
if (this._database == null)
this._database = DatabaseHelper.Instance(Application.Context);
if (intent.Action.Equals(Intents.SyncHeartbeats)) SyncHeartbeatRecords();
var broadcastIntent = new Intent(Intents.MobileRefresh);
SendBroadcast(broadcastIntent);
}
}
Activity, actually a BaseActivity which all Activities inherit from:
[Activity(Label = "BaseActivity")]
public abstract class BaseActivity : AppCompatActivity
{
/// <summary>
/// Reference to the current context.
/// </summary>
protected Context _context { get; set; }
/// <summary>
/// "Tag" used for Log functionallity.
/// </summary>
protected string _tag { get; set; }
/// <summary>
/// Reference To <see cref="RemoteSyncServiceConnection"/>
/// </summary>
protected RemoteSyncServiceConnection _service_connection;
/// <summary>
/// Reference To The Current SessionState.
/// </summary>
protected SessionState _session_state;
/// <summary>
/// Reference To <see cref="SyncReceiver"/>
/// </summary>
protected SyncReceiver _sync_receiver;
/// <summary>
/// Base FloatingActionButton.
/// </summary>
protected FloatingActionButton _base_fab;
/// <summary>
/// Is the Fab Menu Shown / Hid.
/// </summary>
protected static bool _is_fab_open;
protected IConnection _printer_connection;
protected string _printer_address;
protected bool _service_required;
protected bool _receiver_required;
protected MediaPlayer _media_player;
protected DatabaseHelper _database;
/// <summary>
/// <see cref="IntentFilter"/> for the <see cref="SyncReceiver"/>
/// </summary>
protected readonly string[] _intent_filters =
{
Intents.AlarmCompleteOrders,
Intents.AlarmHeartbeats,
Intents.AlarmPkas,
Intents.AlarmTrackingScans,
Intents.MobileRefresh
};
#region Lifecycle Methods
/// <summary>
/// Application Lifecycle Method.
/// </summary>
/// <param name="savedInstanceState"></param>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// *** Initialize Xamarin.Essentials ***
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// *** Initialize the DatabaseHelper ***
if(this._database == null)
this._database = DatabaseHelper.Instance(this.ApplicationContext);
}
}
The DatabaseHelper instance is being disposed of frequently causing either services, or activities to try and access the disposed _database object.
How is this being disposed of and why?
I thought making the _instance static within the DatabaseHelper as well as making the constructor private and forcing the use of the DatabaseHelper.Instance method would keep a single instance of the DatabaseHelper that wouldn't be disposed of between activities and services?
Am I misunderstanding this?
EDIT logcat output from try/catch blocks showing the exception being thrown. The SaveHeartbeat method exists in the base activity.:
protected void SaveHeartbeat(DateTime time, string sourceActivity, [CallerMemberName] string sourceEvent = "")
{
try
{
var heartbeat = new SmartWarehouse.Shared.Models.Heartbeat(sourceActivity,
sourceEvent,
this._session_state.CurrentSession.ROWID.ToString());
this._database.InsertHeartbeat(heartbeat);
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
}
EDIT 2 DatabaseHelper.InsertHeartbeat():
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
Alright so my theory is that when I access the db object in the using() statement it is disposing of the database that the DatabaseHelper object uses. Also noticed that I'm not using db.InsertOrThrow() method which I should be.. Gonna do some re-working on my DatabaseHelper class to see if that resolves the issue.
It turns out that my singleton instance of the DatbaseHelper was not being disposed of.
Actually what was happening is I was disposing of the SQLiteDatabase object that was being used by the DatbaseHelper from within the helper methods.
All I had to do to actually resolve the issue was change:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This using() statement is causing the disposal
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
TO:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This is no longer initialized in a using() statement
var db = this.WritableDatabase;
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
SUMMARY:
By initializing my SQLiteDatabase db object inside of using() statements inside of my helper methods I was disposing of the SQLiteDatabase that my DatabaseHelper needed.
Related
Today my problem is in that i can't deal with the fileSystemWatcher (even with debug).
So... i want to use the function GetHashFromFile(string path, HashAlgorithm algorithm ) while the fileSystemWatcher is watching the choosen directory. Once it gets an change in this directory (File has been created, re-named, change..) i want to use the e.fullPath as 1st argument in GetHashFromFile, but it throws me an exception about that this file can't be found. Could someone tell me on wich place in the code should i use the GetHashFromFile() ?
Thanks !
Here is some sample code which I created for a different SO question which correctly uses FileSystemWatcher to process files which should meet your needs
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Security.Permissions;
namespace ConsoleApplication9
{
internal class Program
{
private static void Main(string[] args)
{
const string directorytowatch = #"d:\junk\watch\"; // the directory to watch for new files
// this initiates a filesystemmonitor to watch for new files being created
Task.Factory.StartNew(() => FileSystemMonitor.Instance.WatchDirectory(directorytowatch));
// initiate the processing of any new files
FilesWorker.Instance.ReadQueue();
Console.ReadLine();
}
}
/// <summary>
/// Monitors the filesystem in "real-time" to check for new files
/// </summary>
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
internal class FileSystemMonitor : SingletonBase<FileSystemMonitor>
{
private FileSystemMonitor()
{
}
internal void WatchDirectory(string dir)
{
var watcher = new FileSystemWatcher(dir)
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.LastAccess,
Filter = "*.*"
};
// watch all files
watcher.Created += WatcherOnCreated;
watcher.EnableRaisingEvents = true;
}
private static void WatcherOnCreated(object sender, FileSystemEventArgs fileSystemEventArgs)
{
Console.WriteLine(fileSystemEventArgs.FullPath + "" + fileSystemEventArgs.ChangeType); // for test purposes
var fileInfo = new FileInfo(fileSystemEventArgs.FullPath);
FilesWorker.Instance.AddToQueue(fileInfo);
}
}
/// <summary>
/// handles the queue of files to be processed and the syncronisation of tasks related to the queue
/// </summary>
internal class FilesWorker : SingletonBase<FilesWorker>
{
private FilesWorker()
{
}
/// <summary>
/// The queue of files which still need to be processed
/// </summary>
private readonly ConcurrentQueue<FileInfo> _filesQueue = new ConcurrentQueue<FileInfo>();
/// <summary>
/// create a semaphore to limit the number of threads which can process a file at any given time
// In this case only allow 2 to be processed at any given time
/// </summary>
private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(2, 2);
/// <summary>
/// add new file to the queue
/// </summary>
/// <param name="fileInfo"></param>
internal void AddToQueue(FileInfo fileInfo)
{
_filesQueue.Enqueue(fileInfo);
}
/// <summary>
/// executes a method on a given timeframe
/// </summary>
/// <param name="method">method to execute</param>
/// <param name="timer">time between execution runs (seconds)</param>
internal void ExecuteMethod(Action method, double timer)
{
IObservable<long> observable = Observable.Interval(TimeSpan.FromSeconds(timer));
// Token for cancelation
var source = new CancellationTokenSource();
observable.Subscribe(x =>
{
var task = new Task(method);
task.Start();
}, source.Token);
}
/// <summary>
/// Get any new files and send for processing
/// </summary>
internal void ReadQueue()
{
// check the queue every two seconds
ExecuteMethod(ProcessQueue, 2d);
}
/// <summary>
/// takes files from the queue and starts processing
/// </summary>
internal void ProcessQueue()
{
try
{
Semaphore.Wait();
FileInfo fileInfo;
while (_filesQueue.TryDequeue(out fileInfo))
{
var fileProcessor = new FileProcessor();
fileProcessor.ProcessFile(fileInfo);
}
}
finally
{
Semaphore.Release();
}
}
}
internal class FileProcessor
{
internal void ProcessFile(FileInfo fileInfo)
{
// do some long running tasks with the file
}
}
/// <summary>
/// Implements singleton pattern on all classes which derive from it
/// </summary>
/// <typeparam name="T">Derived class</typeparam>
public abstract class SingletonBase<T> where T : class
{
public static T Instance
{
get { return SingletonFactory.Instance; }
}
/// <summary>
/// The singleton class factory to create the singleton instance.
/// </summary>
private class SingletonFactory
{
static SingletonFactory()
{
}
private SingletonFactory()
{
}
internal static readonly T Instance = GetInstance();
private static T GetInstance()
{
var theType = typeof(T);
T inst;
try
{
inst = (T)theType
.InvokeMember(theType.Name,
BindingFlags.CreateInstance | BindingFlags.Instance
| BindingFlags.NonPublic,
null, null, null,
CultureInfo.InvariantCulture);
}
catch (MissingMethodException ex)
{
var exception = new TypeLoadException(string.Format(
CultureInfo.CurrentCulture,
"The type '{0}' must have a private constructor to " +
"be used in the Singleton pattern.", theType.FullName)
, ex);
//LogManager.LogException(LogManager.EventIdInternal, exception, "error in instantiating the singleton");
throw exception;
}
return inst;
}
}
}
}
in my main WPF application code i need to run .exe app with command prompt. this action is executed inside backgroundworker i have the following code. the code is running readlines.exe app with command prompt and read the output lines into a string (str).
string str;
ProcessStartInfo proc = new ProcessStartInfo();
proc.WindowStyle = ProcessWindowStyle.Hidden;
proc.UseShellExecute = true;
proc.FileName = #"readlines.exe";
proc.Arguments = #"";
proc.UseShellExecute = false;
proc.RedirectStandardOutput = true;
proc.CreateNoWindow = true;
proc.RedirectStandardInput = true;
Process proc1 = Process.Start(proc);
proc1.StandardInput.WriteLine("");
str = proc1.StandardOutput.ReadToEnd();
i want to ad timeout to the below line so when the timeout will be finised the procces will be canceled (as CTR+C) and "str" will get the output text until this point.
str = proc1.StandardOutput.ReadToEnd();
is it possible?
Although the previous answer has already been accepted here is a maybe more useful, secure and performant solution. Further it does not make use of the ReadLine() method which would block until there has been one line written (which may never occur). It uses an instance of StringBuilder and reads from the stream in specifyable data blocks (default size is 128 characters). Furthermore it supports event based notification of read data.
The usage of the class stays the same.
ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();
// Do whatever you want here
// (e.g. sleep or whatever)
por.StopReading();
// Now you have everything that has been read in por.Data
However I've added the OnDataRead event which is fired every time new data has been read. You can access the data by using e.g. following code:
...
// Subscribe to the event
por.OnDataRead += OnDataReadEventHandler;
...
The callback method / event handler would look something like this:
private void OnDataReadEventHandler(object sender, ProcessOutputReaderEventArgs e)
{
// e.IntermediateDataStore points to the StringBuilder instance which holds
// all the data that has been received until now.
string completeData = e.IntermediateDataStore.ToString();
// e.NewData points to a string which contains the data that has been received
// since the last triggered event (because the event is triggered on each read).
string newData = e.NewData;
}
The modified ProcessOutputReader class looks like this:
/// <summary>
/// Represents the ProcessOutputReader class.
/// </summary>
public class ProcessOutputReader
{
/// <summary>
/// Represents the instance of the thread arguments class.
/// </summary>
private ProcessOutputReaderWorkerThreadArguments threadArguments;
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReader"/> class.
/// </summary>
/// <param name="process">The process which's output shall be read.</param>
/// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified process reference is null.</exception>
public ProcessOutputReader(Process process)
{
if (process == null)
{
throw new ArgumentOutOfRangeException("process", "The parameter \"process\" must not be null");
}
this.Process = process;
this.IntermediateDataStore = new StringBuilder();
this.threadArguments = new ProcessOutputReaderWorkerThreadArguments(this.Process, this.IntermediateDataStore);
}
/// <summary>
/// Is fired whenever data has been read from the process output.
/// </summary>
public event EventHandler<ProcessOutputReaderEventArgs> OnDataRead;
/// <summary>
/// Gets or sets the worker thread.
/// </summary>
private Thread ReaderThread
{
get;
set;
}
/// <summary>
/// Gets or sets the intermediate data store.
/// </summary>
private StringBuilder IntermediateDataStore
{
get;
set;
}
/// <summary>
/// Gets the data collected from the process output.
/// </summary>
public string Data
{
get
{
return this.IntermediateDataStore.ToString();
}
}
/// <summary>
/// Gets the process.
/// </summary>
public Process Process
{
get;
private set;
}
/// <summary>
/// Stars reading from the process output.
/// </summary>
public void StartReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
return;
}
}
this.ReaderThread = new Thread(new ParameterizedThreadStart(ReaderWorker));
this.threadArguments.Exit = false;
this.ReaderThread.Start(this.threadArguments);
}
/// <summary>
/// Stops reading from the process output.
/// </summary>
public void StopReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
this.threadArguments.Exit = true;
this.ReaderThread.Join();
}
}
}
/// <summary>
/// Fires the OnDataRead event.
/// </summary>
/// <param name="newData">The new data that has been read.</param>
protected void FireOnDataRead(string newData)
{
if (this.OnDataRead != null)
{
this.OnDataRead(this, new ProcessOutputReaderEventArgs(this.IntermediateDataStore, newData));
}
}
/// <summary>
/// Represents the worker method.
/// </summary>
/// <param name="data">The thread arguments, must be an instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.</param>
private void ReaderWorker(object data)
{
ProcessOutputReaderWorkerThreadArguments args;
try
{
args = (ProcessOutputReaderWorkerThreadArguments)data;
}
catch
{
return;
}
try
{
char[] readBuffer = new char[args.ReadBufferSize];
while (!args.Exit)
{
if (args.Process == null)
{
return;
}
if (args.Process.HasExited)
{
return;
}
if (args.Process.StandardOutput.EndOfStream)
{
return;
}
int readBytes = this.Process.StandardOutput.Read(readBuffer, 0, readBuffer.Length);
args.IntermediateDataStore.Append(readBuffer, 0, readBytes);
this.FireOnDataRead(new String(readBuffer, 0, readBytes));
}
}
catch (ThreadAbortException)
{
if (!args.Process.HasExited)
{
args.Process.Kill();
}
}
}
}
In addition you need the ProcessOutputReaderWorkerThreadArguments class which looks like this:
/// <summary>
/// Represents the ProcessOutputReaderWorkerThreadArguments class.
/// </summary>
public class ProcessOutputReaderWorkerThreadArguments
{
/// <summary>
/// Represents the read buffer size,
/// </summary>
private int readBufferSize;
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReaderWorkerThreadArguments"/> class.
/// </summary>
/// <param name="process">The process.</param>
/// <param name="intermediateDataStore">The intermediate data store.</param>
public ProcessOutputReaderWorkerThreadArguments(Process process, StringBuilder intermediateDataStore)
{
this.ReadBufferSize = 128;
this.Exit = false;
this.Process = process;
this.IntermediateDataStore = intermediateDataStore;
}
/// <summary>
/// Gets or sets a value indicating whether the thread shall exit or not.
/// </summary>
public bool Exit
{
get;
set;
}
/// <summary>
/// Gets or sets the read buffer size in bytes.
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">Is thrown if the specified value is not greather than 0.</exception>
public int ReadBufferSize
{
get
{
return this.readBufferSize;
}
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException("value", "The specified value for \"ReadBufferSize\" must be greater than 0.");
}
this.readBufferSize = value;
}
}
/// <summary>
/// Gets the process.
/// </summary>
public Process Process
{
get;
private set;
}
/// <summary>
/// Gets the intermediate data store.
/// </summary>
public StringBuilder IntermediateDataStore
{
get;
private set;
}
}
And the ProcessOutputReaderEventArgs class which looks like this:
/// <summary>
/// Represents the ProcessOutputReaderEventArgs class.
/// </summary>
public class ProcessOutputReaderEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="ProcessOutputReaderEventArgs"/> class.
/// </summary>
/// <param name="intermediateDataStore">The reference to the intermediate data store.</param>
/// <param name="newData">The new data that has been read.</param>
public ProcessOutputReaderEventArgs(StringBuilder intermediateDataStore, string newData)
{
this.IntermediateDataStore = intermediateDataStore;
this.NewData = newData;
}
/// <summary>
/// Gets the reference to the intermediate data store.
/// </summary>
public StringBuilder IntermediateDataStore
{
get;
private set;
}
/// <summary>
/// Gets the new data that has been read.
/// </summary>
public string NewData
{
get;
private set;
}
}
Some example how to achieve this (attention, code not tested and can be improved)
ProcessOutputReader por = new ProcessOutputReader(proc1);
por.StartReading();
// Do whatever you want here
// (e.g. sleep or whatever)
por.StopReading();
// Now you have everything that has been read in por.Lines
The class would look like:
public class ProcessOutputReader
{
public ProcessOutputReader(Process process)
{
this.Process = process;
this.Lines = new List<string>();
}
public List<string> Lines
{
get;
private set;
}
public Process Process
{
get;
private set;
}
private Thread ReaderThread
{
get;
set;
}
public void StartReading()
{
if (this.ReaderThread == null)
{
this.ReaderThread = new Thread(new ThreadStart(ReaderWorker));
}
if (!this.ReaderThread.IsAlive)
{
this.ReaderThread.Start();
}
}
public void StopReading()
{
if (this.ReaderThread != null)
{
if (this.ReaderThread.IsAlive)
{
this.ReaderThread.Abort();
this.ReaderThread.Join();
}
}
}
private void ReaderWorker()
{
try
{
while (!this.Process.HasExited)
{
string data = this.Process.StandardOutput.ReadLine();
this.Lines.Add(data);
}
}
catch (ThreadAbortException)
{
if (!this.Process.HasExited)
{
this.Process.Kill();
}
}
}
}
Today I've discovered that the FW 4.5 has their own undoredo manager (if I understood good) http://msdn.microsoft.com/en-us/library/System.ComponentModel.Design.UndoEngine%28v=vs.110%29.aspx
Well, I can't find any example about how to start using this class just to make a simple undo/redo of a text based control, I know other alternatives to do undoable things, but just I want to learn how to use this.
When I try to use the constructor it has any parameter to be passed, and also the Intellisense does not shows me any method for the System.ComponentModel.Design.UndoEngine class, really I don't know how I could use it.
Someone could illustrate ours with an example for C# or VBNET? (I preffer VBNET documentation if possibly, please)
UndoEngine is an abstract class, Visual Studio and Designers have implemented UndoEngine in their own way, and those must be private or not available for redistribution. You will not be able to use it, in fact abstract class is just an interface with little implementation, it is not at all an undo framework.
You still have to write your own undo management, however benefit of deriving your undo engine from UndoEngine class is, it can be easily hosted/integrated with VS and other MS based editors.
If you want to provide an editing experience inside Visual Studio document editor, then you have to derive your Undo framework class from UndoEngine, VS will automatically highlight disable undo/redo buttons and will call undo/redo methods on your class.
If you want to use UndoEngine inside your own application, UndoEngine will not help you for anything, you will have to write every functionality by yourself. UndoEngine just manages stack of Undo/Redo, real work is inside UndoUnit. It is based on Unit of Work concept, where your every action should actually represent a work that can be undone.
The simplest UndoEngine Implementation
Let us say you are changing a global variable,
// following code uses big UndoUnit
public void SetGlobalVariable(object v){
var oldValue = GlobalVariable;
GlobalVariable = v;
var action = new UndoUnit{
UndoAction = ()=>{
GlobalVariable = oldValue;
},
RedoAction = ()=>{
GlobalVariable = v;
}
};
UndoManager.Add(action);
}
/// <summary>
/// Used to indicates the designer's status
/// </summary>
public enum UndoUnitState
{
Undoing,
Redoing,
}
/// <summary>
/// A UndoUnitBase can be used as a IOleUndoUnit or just a undo step in
/// a transaction
/// </summary>
public class UndoUnitBase : IOleUndoUnit
{
public Action UndoAction {get;set;}
public Action RedoAction {get;set;}
private string name = null;
private Guid clsid = Guid.Empty;
private bool inDoAction = false;
private bool isStillAtTop = true;
private UndoUnitState unitState = UndoUnitState.Undoing;
protected UndoUnit UnitState
{
get { return unitState; }
set { unitState = value; }
}
/// <summary>
/// </summary>
/// <param name="undoManager"></param>
/// <param name="name"></param>
internal UndoUnitBase(string name)
{
this.name = name;
}
~UndoUnitBase()
{
}
/// <summary>
/// </summary>
protected bool InDoAction
{
get
{
return inDoAction;
}
}
public string UndoName
{
get
{
return name;
}
set
{
this.name = value;
}
}
public Guid Clsid
{
get { return clsid; }
set { clsid = value; }
}
/// <summary>
/// This property indicates whether the undo unit is at the top (most recently added to)
/// the undo stack. This is useful to know when deciding whether undo units for operations
/// like typing can be coallesced together.
/// </summary>
public bool IsStillAtTop
{
get { return isStillAtTop; }
}
/// <summary>
/// This function do the actual undo, and then revert the action to be a redo
/// </summary>
/// <returns>objects that should be selected after DoAction</returns>
protected abstract void DoActionInternal();
/// <devdoc>
/// IOleUndoManager's "Do" action.
/// </devdoc>
void IOleUndoUnit.Do(IOleUndoManager oleUndoManager)
{
Do(oleUndoManager);
}
protected virtual int Do(IOleUndoManager oleUndoManager)
{
try
{
if(unitState== UndoUnitState.Undoing){
UndoAction();
}else{
RedoAction();
}
unitState = (unitState == UndoUnitState.Undoing) ? UndoUnitState.Redoing : UndoUnitState.Undoing;
if (oleUndoManager != null)
oleUndoManager.Add(this);
return VSConstants.S_OK;
}
catch (COMException e)
{
return e.ErrorCode;
}
catch
{
return VSConstants.E_ABORT;
}
finally
{
}
}
/// <summary>
/// </summary>
/// <returns></returns>
void IOleUndoUnit.GetDescription(out string pBstr)
{
pBstr = name;
}
/// <summary>
/// </summary>
/// <param name="clsid"></param>
/// <param name="pID"></param>
/// <returns></returns>
void IOleUndoUnit.GetUnitType(out Guid pClsid, out int plID)
{
pClsid = Clsid;
plID = 0;
}
/// <summary>
/// </summary>
void IOleUndoUnit.OnNextAdd()
{
// We are no longer the top most undo unit; another one was added.
isStillAtTop = false;
}
}
public class MyUndoEngine : UndoEngine, IUndoHandler
{
Stack<UndoEngine.UndoUnit> undoStack = new Stack<UndoEngine.UndoUnit>();
Stack<UndoEngine.UndoUnit> redoStack = new Stack<UndoEngine.UndoUnit>();
public ReportDesignerUndoEngine(IServiceProvider provider) : base(provider)
{
}
#region IUndoHandler
public bool EnableUndo {
get {
return undoStack.Count > 0;
}
}
public bool EnableRedo {
get {
return redoStack.Count > 0;
}
}
public void Undo()
{
if (undoStack.Count > 0) {
UndoEngine.UndoUnit unit = undoStack.Pop();
unit.Undo();
redoStack.Push(unit);
}
}
public void Redo()
{
if (redoStack.Count > 0) {
UndoEngine.UndoUnit unit = redoStack.Pop();
unit.Undo();
undoStack.Push(unit);
}
}
#endregion
protected override void AddUndoUnit(UndoEngine.UndoUnit unit)
{
undoStack.Push(unit);
}
}
If your question is how to use it at runtime, then the answer is in MSDN:
Specifies generic undo/redo functionality at design time.
So I doubt that it is easily usable at runtime.
If you meant an example of custom user control utilizing this class, I can't find any, sorry.
Find an implementation of the UndoEngine and how to use it right here:
https://github.com/icsharpcode/SharpDevelop/search?q=ReportDesignerUndoEngine&ref=cmdform
HTH
I have quite a complicated programming problem on my hands, so bear with me for a few minutes.
I decided i want to create a media player in WPF (C#) and i've run into a bit of a pickle.
I want my application to be single instance, so that when the user double clicks server files, the program would only run once and queue all files for playing.
I tried several ways of doing it, including Microsoft's single instance implementation, and nothing seemed to work, until i decided to create my own, as in i though of something and implemented it (this probably was on the internet somewhere as well, but it didn't show up)
Basically, i use a named mutex to prevent more than one instance from being opened, and to force the other instances to write their arguments to a file, and after that, the instance which created the mutex would read the file.
Needless to say, this is very, very ineffective as far as performance goes, but anyway, here is my implementation of the Main() function.
Note that this Main() is also written from scratch, as i didn't really like the one automatically generated by the VS2010.
static void Main(string[] args)
{
string[] arguments = new string[0];
handler g = new handler();
bool createdNew = false;
Mutex lolpaca = new Mutex(true, "lolpacamaximumtrolololololol", out createdNew);
if (createdNew)
{
if (args != null)
{
var MainWindow = new MainWindow();
var app = new Application();
app.Run(MainWindow);
lolpaca.ReleaseMutex();
lolpaca.Dispose();
}
else
{
Array.Resize(ref arguments, 1);
arguments[0] = args[0];
string line;
//nu mai arunca exceptii nenorocitule
while ((line = g.ReadArgs()) != null)
{
int old_size = arguments.Length;
Array.Resize(ref arguments, arguments.Length + 1);
arguments[old_size] = line;
}
var MainWindow = new MainWindow(arguments, arguments.Length);
var app = new Application();
app.Run(MainWindow);
lolpaca.ReleaseMutex();
lolpaca.Dispose();
}
if (File.Exists(path))
{
File.Delete(path);
}
}
else
{
Thread writer = new Thread(new ParameterizedThreadStart(g.WriteArg));
writer.Start(args);
writer.Join();
try
{
g.WriteArg(args);
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
}
}
}
I'm also using this class to attempt to sync between the threads
public class handler
{
static string path = #"D:\playlist.txt";
static FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
string line;
string arg;
bool readerFlag = false;
public string ReadArgs()
{
try
{
lock (fs) // Enter synchronization block
{
if (!readerFlag)
{ // Wait until writer finishes
try
{
// Waits for the Monitor.Pulse in WriteArg
Monitor.Wait(fs);
}
catch (SynchronizationLockException)
{
}
catch (ThreadInterruptedException)
{
}
}
TextReader tr = new StreamReader(fs);
while ((line = tr.ReadLine()) != null)
{
arg = line;
}
tr.Close();
tr.Dispose();
}
/* fs.Close();
fs.Dispose();*/
readerFlag = false;
Monitor.Pulse(fs);
return arg;
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
return null;
}
}
public void WriteArg(object args)
{
lock (fs)
{
try
{
if (readerFlag)
{
try
{
Monitor.Wait(fs); // Wait for the Monitor.Pulse in ReadArgs
}
catch (SynchronizationLockException)
{
}
catch (ThreadInterruptedException)
{
}
}
arg = Convert.ToString(args);
// FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read);
TextWriter tw = new StreamWriter(fs);
tw.WriteLine(args);
tw.Close();
tw.Dispose();
}
catch (IOException e)
{
MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source);
exp.Show();
}
}
/* fs.Close();
fs.Dispose();*/
readerFlag = true;
Monitor.Pulse(fs);
}
}
Now, basically, for each double clicked file, one instance of the Main() function is created by Windows.
The first instance has control over the mutex and proceeds to doing whatever it wants to do.
The other instances must write their argument to the file.
Now, the problem:
Apparently, the threads (all of them) do no sync properly, and sometimes i get IO exceptions.
I have no clue where exactly these exceptions are thrown, because the try-catch blocks seem to do exactly nothing. In fact, I believe this is a little deeper than try-catch would work on.
So, how do i sync all the threads that spawn when the user double clicks a lot of files? This implementation works ok with up to 3 double clicked files, and sometimes (note, sometimes it works, other times it doesn't) with more than 3 files (tested with up to 9).
Nothing i found so far on the internet accounts for several instances of the same application running independently.
It would be great if you could give me an example:)
Thank you.
The best way to talk between two instances of the same application is use IPC. Bellow see example of class that can be used to help with single instance:
/// <summary>
/// Enforces single instance for an application.
/// </summary>
public class SingleInstance : IDisposable
{
#region Fields
/// <summary>
/// The synchronization context.
/// </summary>
private readonly SynchronizationContext synchronizationContext;
/// <summary>
/// The disposed.
/// </summary>
private bool disposed;
/// <summary>
/// The identifier.
/// </summary>
private Guid identifier = Guid.Empty;
/// <summary>
/// The mutex.
/// </summary>
private Mutex mutex;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="SingleInstance"/> class.
/// </summary>
/// <param name="identifier">
/// An identifier unique to this application.
/// </param>
/// <param name="args">
/// The command line arguments.
/// </param>
public SingleInstance(Guid identifier, IEnumerable<string> args)
{
this.identifier = identifier;
bool ownsMutex;
this.mutex = new Mutex(true, identifier.ToString(), out ownsMutex);
this.synchronizationContext = SynchronizationContext.Current;
this.FirstInstance = ownsMutex;
if (this.FirstInstance)
{
this.ListenAsync();
}
else
{
this.NotifyFirstInstance(args);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SingleInstance"/> class.
/// </summary>
/// <param name="identifier">
/// An identifier unique to this application.
/// </param>
public SingleInstance(Guid identifier)
: this(identifier, null)
{
}
#endregion
#region Public Events
/// <summary>
/// Event raised when arguments are received from successive instances.
/// </summary>
public event EventHandler<OtherInstanceCreatedEventArgs> OtherInstanceCreated;
#endregion
#region Public Properties
/// <summary>
/// Gets a value indicating whether this is the first instance of this application.
/// </summary>
public bool FirstInstance { get; private set; }
#endregion
#region Implemented Interfaces
#region IDisposable
/// <summary>
/// The dispose.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#endregion
#region Methods
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">
/// True if managed resources should be disposed; otherwise, false.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (this.disposed)
{
return;
}
if (disposing)
{
if (this.mutex != null && this.FirstInstance)
{
this.mutex.WaitOne();
this.mutex.ReleaseMutex();
this.mutex = null;
}
}
this.disposed = true;
}
/// <summary>
/// Fires the OtherInstanceCreated event.
/// </summary>
/// <param name="arguments">
/// The arguments to pass with the <see cref="OtherInstanceCreatedEventArgs"/> class.
/// </param>
protected virtual void OnOtherInstanceCreated(OtherInstanceCreatedEventArgs arguments)
{
EventHandler<OtherInstanceCreatedEventArgs> handler = this.OtherInstanceCreated;
if (handler != null)
{
handler(this, arguments);
}
}
/// <summary>
/// Listens for arguments on a named pipe.
/// </summary>
private void Listen()
{
try
{
using (var server = new NamedPipeServerStream(this.identifier.ToString()))
{
using (var reader = new StreamReader(server))
{
server.WaitForConnection();
var arguments = new List<string>();
while (server.IsConnected)
{
arguments.Add(reader.ReadLine());
}
this.synchronizationContext.Post(o => this.OnOtherInstanceCreated(new OtherInstanceCreatedEventArgs(arguments)), null);
}
}
// start listening again.
this.Listen();
}
catch (IOException)
{
// Pipe was broken, listen again.
this.Listen();
}
}
/// <summary>
/// Listens for arguments being passed from successive instances of the applicaiton.
/// </summary>
private void ListenAsync()
{
Task.Factory.StartNew(this.Listen, TaskCreationOptions.LongRunning);
}
/// <summary>
/// Passes the given arguments to the first running instance of the application.
/// </summary>
/// <param name="arguments">
/// The arguments to pass.
/// </param>
private void NotifyFirstInstance(IEnumerable<string> arguments)
{
try
{
using (var client = new NamedPipeClientStream(this.identifier.ToString()))
{
using (var writer = new StreamWriter(client))
{
client.Connect(200);
if (arguments != null)
{
foreach (string argument in arguments)
{
writer.WriteLine(argument);
}
}
}
}
}
catch (TimeoutException)
{
// Couldn't connect to server
}
catch (IOException)
{
// Pipe was broken
}
}
#endregion
}
/// <summary>
/// Holds a list of arguments given to an application at startup.
/// </summary>
public class OtherInstanceCreatedEventArgs : EventArgs
{
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="OtherInstanceCreatedEventArgs"/> class.
/// </summary>
/// <param name="args">
/// The command line arguments.
/// </param>
public OtherInstanceCreatedEventArgs(IEnumerable<string> args)
{
this.Args = args;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the startup arguments.
/// </summary>
public IEnumerable<string> Args { get; private set; }
#endregion
}
Then in your main class you can create instance of of class that will stay until aplication is running. You can check if other instance is created by FirstInstance property, And get notified of other instance created by OtherInstanceCreated event.
I just can't make out if the entity context is disposed in the usage flow when used in a using statement in a web application or a console application.
Thanks!
using System;
using System.Web;
namespace Foo.Model
{
public partial class FooEntities : ObjectContext
{
private const string CurrentContextKey = "FooEntities.Current";
[ThreadStatic]
private static FooEntities _currentOnThreadStatic;
private FooEntities _previousContext;
/// <summary>
/// Gets the current <see cref="FooEntities"/> instance, if an instance can be shared in the current context.
/// </summary>
/// <remarks>
/// The current context is stored in the HTTP context, if it is available (otherwise it is stored in a thread-static instance).
/// Multiple contexts can be stacked.
/// </remarks>
public static FooEntities Current
{
get
{
if (HttpContext.Current != null)
{
return HttpContext.Current.Items[CurrentContextKey] as FooEntities;
}
else
{
return _currentOnThreadStatic;
}
}
private set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[CurrentContextKey] = value;
}
else
{
_currentOnThreadStatic = value;
}
}
}
/// <summary>
/// Returns a repository instance bound to this object context.
/// </summary>
/// <typeparam name="TRepository">The type of repository to instantiate.</typeparam>
/// <returns>The repository instance.</returns>
public TRepository GetRepository<TRepository>()
where TRepository: BaseRepository
{
return (TRepository) Activator.CreateInstance(typeof(TRepository), this);
}
/// <summary>
/// Ensures that an ambient context is available through <see cref="Current"/>, throwing an exception otherwise.
/// </summary>
/// <exception type="InvalidOperationException)">
/// Thrown if <see cref="Current"/> is null.
/// </exception>
public static void EnsureContext()
{
if (Current == null)
{
throw new InvalidOperationException("An ambient FooEntities context is expected.");
}
}
/// <summary>
/// Releases the context instance.
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
Current = _previousContext;
base.Dispose(disposing);
}
/// <summary>
/// Is called by all constructors.
/// </summary>
partial void OnContextCreated()
{
_previousContext = Current;
Current = this;
}
}
}
It is an odd design. As #Joel C points out in his comment you should regard the object context as a shortlived object that you create when you need it and release right afterwards.
But I see no reason that this would leak memory. You are only dealing with managed resources and you are using the same key all the time to the HttpContext so you won't create new objects all over.