I have a WPF application with code written in C#, developed in Visual Studio 2013. This is a GUI solution and has many interdependent projects, complete with buttons, fields, menus, checkboxes and text.
My goal is to create a log file (a txt file will do) of all actions that an end user takes while using this application. Example actions could be a button-click, writing in a blank text field, (de)select a check-box, close an activity/tab, etc. I want to capture all such user interactions in the application UI, and have those actions stored as summarized one line descriptions of the action in a text log file.
One way to do this could be to update the event handlers of all the aforementioned elements (button, textfield, ...) with the code to write a summary of the action to append to a txt log file. For example, in an accept button click handler:
private void buttonAccept_Click(object sender, EventArgs e)
{
// TODO: default button click handler code...
// TODO: ...and the code to write the event to a txt log file
}
But this strategy will be very painful to accomplish, having to update each and every event handler (and even write event handlers for elements which don't have any currently).
I am looking for a simpler way in which this could be achieved. Some ideas that I have are:
One way is changing the event handler base class (that all other event handlers inherit from?) to contain the log file writing code. This way the log file code will need to be written only once, and it will be called whenever any event handler is called, which is what we want (There needs to be a distinction made between a user generated events and an app generated event, which can prove difficult in case of event chaining. So this could be a challenge).
Another way is using some "sniffer" which works like a debugger and stores the stack trace of an application's methods, as the user moves through it. This would give us only a partial idea of the user's workflows.
private void buttonAccept_Click(object sender, EventArgs e)
private bool IsValidName(string userName)
private void buttonCancel_Click(object sender, EventArgs e)
private void Close()
...
Adding a time stamp to the message would be useful...
3/1/2015 18:19 private void buttonAccept_Click(object sender, EventArgs e)
3/1/2015 18:19 private bool IsValidName(string userName)
3/1/2015 18:21 private void buttonCancel_Click(object sender, EventArgs e)
3/1/2015 18:21 private void Close()
...
... because, deleting the messages which have a time stamp difference from that of the previous message below a suitable threshold, would leave only the methods that were directly called by the user actions. Assuming that methods signatures are descriptive enough, this message list could work as the desired log file.
3/1/2015 18:19 private void buttonAccept_Click(object sender, EventArgs e)
3/1/2015 18:21 private void buttonCancel_Click(object sender, EventArgs e)
...
However, this will only work for elements that have event handlers associated with them. Still, it's better than the brute force method.
I am having some difficulty in coming up with a way to implement these ideas. Can anyone elaborate on how they could be implemented? Or if you can come up with better ways to make the log file, please share your ideas and also how it can be developed. Thank you!
So, it's WPF; and if correctly written, it's also MVVM. Then you can decorate your viewmodels and capture all the bindings that change. The below example will demonstrate this. For button clicks, you can use the similar approach, except you will be intercepting the ICommand
instances and listening to their events.
For example, let's say you have your regular viewmodel defined (pseudo code) that has two-way property called SimpleProperty
:
class SimpleViewModel : IViewModel
{
public string SimpleProperty { get; set; }
}
To add logging, define a decorator as shown below (again pseudo code):
class LoggerViewModel : IViewModel
{
private readonly IViewModel _originalVM;
private readonly static Logger _logger = new Logger();
public LoggerViewModel(IViewModel originalVM)
{
_originalVM = originalVM;
}
public string SimpleProperty
{
get
{
_logger.Log("Page requested SimplePriperty and value is " + _originalVM.SimpleProperty);
return _originalVM.SimpleProperty;
}
set
{
_logger.Log("Page changed SimpleProperty and value is " + _originalVM.SimpleProperty);
_originalVM.SimpleProperty = value;
}
}
}
Obviously, the IViewModel interface looks like this:
interface IViewModel
{
string SimpleProperty { get; set; }
}
Look into Microsoft UI Automation to see if it meets your needs. It includes the ability to be notified of events, which looks like what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With