Show dialog from non UI dll - c#

I'm building a dll that will be used from wpf and other kind of framework (windows form, asp...). For this reason I don't want to use Messagebox. Which is the best way to send notification from dll to app and each decide the way to show the message to user (and wait an answer from user)? Somebody can help me to find the correct way?

Unless the library (.dll) is only intended to work with a particular UI, the library shouldn't "decide" how or if notifications get displayed. It's a separation of concerns. If a library determined that it should show a MessageBox then you wouldn't be able to use that same library with a web app or some out-of-sight service.
Here are two ways (not exhaustive) that we might get information from a separate library, including our own:
We call a function and the library returns a response. For example, it might indicate that an action succeeded or failed. The library doesn't know what type of app it's being called from or whether anyone needs to see the response. It just returns it. Your app can then receive that result and display a message.
A class within the library raises an event which indicates that something has happened. Same thing - it doesn't know what is listening for that even or what will happen as a result. It just raises the notification. Our app determines that in response to that event it should display a message.
When our libraries work that way they are easier to test using automated tests like unit tests and integration tests. It's easy to write a test which verifies that calling a method returns a certain result. It's much harder to verify that a MessageBox pops up.
And, as mentioned, it makes it more likely that we can use more of our code with different types of user interfaces. For those reasons it's beneficial to write as much of our code as possible in isolation from any UI, which means not including input/output behaviors that are specific to one type of UI.

You could expose an event that the consumers can subscribe to. Here is the general pattern to do this kind of thing:
You can create your own class to carry the data about the event:
public class NotificationEventArgs : EventArgs
{
public NotificationEventArgs(string message)
{
Message = message;
}
public string Message { get; }
}
You then create a delegate to represent the signature of the event:
public delegate void OnNotificationEventHandler(SomeClass sender, NotificationEventArgs args);
Your class or classes can then expose this delegate as an event:
public class SomeClass
{
private OnNotificationEventHandler _notificationEventHandler;
public event OnNotificationEventHandler OnNotification
{
add { _notificationEventHandler += value; }
remove { _notificationEventHandler -= value; }
}
protected void RaiseNotificationEvent(NotificationEventArgs args)
{
_notificationEventHandler?.Invoke(this, args);
}
public void SomeMethod()
{
//Your class does something that requires consumer notification
var args = new NotificationEventArgs("Something happened!");
//Raise the event for the consumers who are listening (if any)
RaiseNotificationEvent(args);
}
}
Finally, your consuming classes will subscribe to this event:
SomeClass obj = new SomeClass();
obj.OnNotification += Obj_OnNotification;
private static void Obj_OnNotification(SomeClass sender, NotificationEventArgs args)
{
//Handle the notification from the class here.
Console.WriteLine(args.Message);
}
The general idea is that consumers of your class only need to know that something has happened as well as details of what happened. How that event is consumed, handled or displayed is not the responsibility of your component.

Related

In Event Tracing for Windows (ETW), how do I use EventSource to point to Notepad and retrieve the menu item selected in an ETW Session?

I am trying to understand Event Tracing in Windows (ETW). What I want to do is capture which menu item was selected in Notepad. If I click Word Wrap, I want ETW to tell me this.
I have looked at the samples on GitHub. One of the Event Producers is the demo:
namespace TraceEventSamples
{
// In these demos, we generate events with System.Diagnostics.Tracing.EventSource and read them with ETWTraceEventSource
//
// Normally the EventSource and the ETWTraceEventSource would be indifferent processes, however, we
// don't do this here to make the scenario really easy to run. The code works in the multi-process case, however.
namespace Producer
{
[EventSource(Name = "Microsoft-Demos-SimpleMonitor")] // This is the name of my eventSource outside my program.
class MyEventSource : EventSource
{
// Notice that the bodies of the events follow a pattern: WriteEvent(ID, <args>) where
// ID is a unique ID starting at 1 and incrementing for each new event method. and
// <args> is every argument for the method.
// WriteEvent then takes care of all the details of actually writing out the values complete
// with the name of the event (method name) as well as the names and types of all the parameters.
public void MyFirstEvent(string MyName, int MyId) { WriteEvent(1, MyName, MyId); }
public void MySecondEvent(int MyId) { WriteEvent(2, MyId); }
public void Stop() { WriteEvent(3); }
// Typically you only create one EventSource and use it throughout your program. Thus a static field makes sense.
public static MyEventSource Log = new MyEventSource();
// You don't need to define this override, but it does show you when your eventSource gets commands, which
// is helpful for debugging (you know that your EventSource got the command.
protected override void OnEventCommand(EventCommandEventArgs command)
{
EventGenerator.Out.WriteLine("EventSource Gets command {0}", command.Command);
}
// We could add Keyword definitions so that you could turn on some events but not others
// but we don't do this here to keep it simple. Thus you either turn on all events or none.
}
This is creating events for the demo, but how can I wire this to Notepad instead? Can ETW be used for this type of logging, knowing what someone clicked on a menu of an application?
I have looked at various SO questions, but they did not help. One generic was, Is there a Microsoft (built-in) ETW Provider for tracing ETW lifecycle events?
I considered this because it does not require C#, C++ Event Tracing for Windows (ETW) wrapper but didn't understand how it helped me.
This makes me think I cannot do it with managed code if I didn't write the original program:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.tracing.eventsource?redirectedfrom=MSDN&view=netcore-3.1
What I am attempting to do is capture which menu item is selected, and take action with my program that caught the event. The reason for this is an old VB6 program. I cannot do what I need to do, so my last resort is to capture the menu item and get my application to do what I want. I wanted to start with a simple notepad.exe.
VB6 user clicks "View X." My C# application does "View Y".

How to capture all user actions in a WPF application to store them in a log file?

Introduction
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.
Logging user actions
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.
Possible solutions
Brute force method
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).
Better way(s)
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.
Suggestion(s)?
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.
Example
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.
The most simple and straightforward way would be intercepting all of your application's windows messages and storing the information you need for the messages you need.
The most straightforward way to achieve this is to make a "message filter" (Application.AddMessageFilter). It looks something like this:
public class GlobalMessageLogger : IMessageFilter{
private const int WM_LBUTTONDOWN = 0x201;
public bool PreFilterMessage(ref Message message){
if (message.Msg == WM_LBUTTONDOWN) {
//Log message
}
return false;
}
}
Then you can do this:
Application.AddMessageFilter(new GlobalMessageLogger());
You can use the Message struct members (of the message parameter) to get more info on a specific message. You'd have to read up on specific Windows messages, their codes (stored in the Msg param), and their wParam and lParam values. To find out what part of your application sent a specific message, you can use the HWnd property.
This is a pretty low-level approach, but it gives you great flexibility (you're not limited to UI elements that actually have event handlers), and makes changes for logging purposes hihgly localized.

A simple .NET messaging system

I am trying to create a system to send messages between components in C# (using the Mono runtime). Here is some pseudo-code of what I am trying to achieve in terms of functionality:
Creating the Message
MyMessage : BaseMessage {}
AnotherMessage : BaseMessage { string data; }
Subscribing
MyMessage.Subscribe(MyMessageHandler)
AnotherMessage.Subscribe(AnotherMessageHandler)
Message Handlers
void MyMessageHandler(MyMessage message)
{
// code
}
void AnotherMessageHandler(AnotherMessage message)
{
// code
}
Sending the Message
MyMessage.Send(MyMessageInstance);
AnotherMessage.Send(AnotherMessageInstance);
Additional Information
Each message handler will only take one type of message, and that message may or may not have a payload of any type (for example a string called data).
I have a working solution in C++ (see below for the subscribing part):
// A function-style macro is used to call this method
template <typename Type, typename Caller>
void subscribe(boost::function<void(const Type&)> subscriber, boost::shared_ptr<Caller> caller)
{
m_subscriptions[typeid(Type)].connect(Subscribers::slot_type([subscriber](const BaseMessage& message)
{
subscriber(static_cast<const Type&>(message));
}).track(caller));
}
For those not familiar with boost::signals2, .track creates a weak pointer to the caller and disconnects the subscriber when it is destroyed.
I am aiming for something similar in C#, but am struggling to do so. This is what I have so far:
abstract class Message<MessageArgType>
{
public delegate void Handler(MessageArgType arg);
private event Handler subscribers;
public void Subscribe(Handler subscriber)
{
subscribers += subscriber;
}
public void Unsubscribe(Handler subscriber)
{
subscribers -= subscriber;
}
public void Send(MessageArgType arg)
{
subscribers.Invoke(arg);
}
}
It seems to me that this will store a strong reference to the object that the message handler belongs to. After a lot of googling, I ended up finding this. However, as someone quite new to C#, I found this quite difficult to grasp what was going on. Also, this post was made in 2007, so there may be a better solution now, but I am struggling to find one.
To conclude
Could someone please provide me with some guidance on how to get a weak reference from a delegate in a thread-safe (due to the GC running on another thread) manner that can achieve an interface similar to the pseudo code above?
In a case of "No matter how much you know, there's always plenty more", I did some more research and discovered that .NET 3 added the WeakEventManager class.
http://msdn.microsoft.com/en-us/library/aa970850(v=vs.110).aspx
To use the Generic WeakEventManager class, do this:
WeakEventManager<EventSource, SomeEventEventArgs>
.AddHandler(source, "SomeEvent", source_SomeEvent);
EDIT:
In your case, you would probably do something like this:
public void Subscribe(Handler subscriber)
{
WeakEventManager<Message, MessageArgType>
.AddHandler(this, "subscribers", subscriber);
}

How to use multiple IEventAggregator for a Single Window in Caliburn Micro?

I have a ShellWindow which has a IEventAggregator and all my child publish to this IEventAggregator?.
Now i have a static class named JIMSMessage in which i publish to IEventAggregator of ShellViewModel.
public static class JIMSMessage
{
public static bool Show(IEventAggregator _events, string message)
{
_events.Publish(new Message()
{
MessageValue = message
});
return true;
}
}
I want my return value of Show method to come from the ViewModel, which calls this method..
Lets say...
I have a ViewModel named LedgerViewModel, this calls the JIMSMessage.Show as follows,
JIMSMessage.Show(_events,"Enter Ledger Name.");
Its working, but my MessageWindowViewModel returns something, which i want to return to JIMSMessage class, how can i do this. Please help me.
I don't think the EventAggregator is really meant to work that way. It is used to Publish events for anyone who cares to receive those events, or to Subscribe to events if something is interested in being alerted about an event.
It is not meant to be used to make a call and wait for a return value within the same method.
What you could do instead is publish something like a ShowMessage event, and subscribe to receive a MessageShown event.
For example, your ShellViewModel might subscribe to receive MessageDisplayed event messages and handle them like this:
public ShellViewModel(IEventAggregator events)
{
// Subscribe to MessageDisplayed events
events.GetEvent<MessageDisplayedEvent>().Subscribe(HandleMessageDisplayed);
}
void HandleMessageDisplayed(MessageDisplayedEvent e)
{
if (e.SomeBooleanProperty)
// Do Work
}
and elsewhere in your application you could publish a ShowMessage event to display a message
// Broadcast an Event
_events.GetEvent<ShowMessageEvent>().Publish(
new ShowMessageEvent{ Message = "Enter Ledger Name." });
And whatever class is responsible for displaying messages would subscribe to receive ShowMessageEvent, show the message, wait for user feedback, then broadcast a MessageDisplayed event with the results when its finished.
Also if you're interested, I wrote a Static class for the EventAggregator that makes dealing with PRISM's EventAggregator much simpler. You might be interested in checking it out.

XAML C# Function across multiple windows

I've got a program I am working on that has multiple windows. The windows are similar in functionality and I want to have a single event handler to cover a button press event for each window in the application. Is this possible?
If you need to bind a handler in code behind you can encapsulate a handler by delegate and inject into the Windows which are required it.
For instance using Action<T>:
Action<string> commonHandler = (parameter) =>
{
// handler code here
};
class MyWindiow
{
public MyWindiow(Action<string> handler)
{
// store to local and assign to button click
// button.CLick += (o, e) => { handler(parameterToBepassed); }
}
}
I'd look into using a framework to help you out here. My favorite is Prism v4.
If you follow the M-V-VM design pattern you're life will be a lot easier. You'll need to understand Data Binding and DataContext.
That being said, if you decide to go this path, you can bind each of your windows to a command:
<Button Command="{Binding DoFooCommand}" Content="DoFoo"/>
You're ViewModel would have a DelegateCommand member to execute.
public class SomeViewModel : NotificationObject
{
public SomeViewModel()
{
DoFooCommand = new DelegateCommand(ExecuteFoo);
}
public DelegateCommand DoFooCommand { get; set; }
private void ExecuteFoo()
{
//Use the EventAggregator to publish a common event
}
}
And finally, somewhere else in your solution you'll have a code file/class that subscribes to the event and waits for someone to publish the event to process it.
public class SomeOtherPlace
{
public SomeOtherPlace()
{
//Use the EventAggregator to subscribe to the common event
}
public void FooBarMethodToCallWhenEventIsPublished(SomePayload payload)
{
//Do whatever you need to do here...
}
}
I realize some of the things were left out (such as what a "SomePayload" is... look into the EventAggregator information), but I did not want to get into it too much. Just give you a guide on where to go for information and some base code to work off of. If you decide to use the EventAggregator then you'll need to ensure that your subscribing call and publishing calls are utilizing the SAME instance of the EventAggregator. You can do this by looking into MEF. Prism is setup to work with MEF perfectly... I'm not going to lie. Doing all this requires a bit of a learning curve, but it will be worthwhile in the end when you can unit test your ViewModels easily and have your code loosely coupled. The EventAggregator is a great way for different classes to communicate to each other without relying on knowing about each other. And MEF is great for having a Container for your services that you want to utilize across your application.
Hope that gave you a bit of insight on how to go about doing what you want to do on the correct path.

Categories

Resources