I'm working on a virtual keyboard, but i struggle to send Keys. Nothing happens, except when i hard-add them to the textbox. Here's my code
public static void Send(Key key)
{ //Found online
var e = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, key)
{
RoutedEvent = Keyboard.KeyDownEvent
};
InputManager.Current.ProcessInput(e);
}
private void ClickOnKey(object sender, RoutedEventArgs e)
{
CustomButton cb = sender as CustomButton;
string text = cb.text;
Console.WriteLine(text);
element_to_focus.Focus(); //The textbox
Send(translate_string_to_key(text));
}
ProcessInput seems to only raise the appropriate key-related events, but will not actually modify the text.
If you really want to simulate key presses, you'll need to leverage p/invoke and use SendInput. Luckily, someone's already done the p/invoke work for us and has made their work available:
https://archive.codeplex.com/?p=inputsimulator
It's also available as a NuGet package (I found two versions):
https://www.nuget.org/packages/InputSimulator/
https://www.nuget.org/packages/InputSimulatorPlus/
Related
My WPF application is creating multiple WebBrowser controls. I know how to manipulate the HtmlDocument within each and also how to handle mouse events on them.
However, from within a mouse event which has a IHTMLEventObj2 object as parameter, how can I retrieve the hosting WebBrowse?
I can get to the document through the srcElement.document but how do I 'navigate up' to the WebBrowser that is hosting this document?
I thought of using a 'Tag' property, but HTMLDocument does not have one.
As a last resort, I probably could use a hash table based on the HtmlDocument object, but this is a bit complicated for such a simple thing ...
Where/how do you get your mouse event and srcElement.document? It seems like javascript.
If true, then I'm pretty sure you can't access the web control from JavaScript, because the web control is not exposed within the DOM tree. You could try to use window.external (or similar) and to expose methods through it, and then have the methods operate on the webbrowser, but that'd be a little convoluted, but I'm sure this way it is possible.
If not true and if you have some mouseevent handler in C#, then simply link the handler with the webbrowser before the event is invoked. Instead of:
// inside your Window/etc:
private int otherData;
private void MyHandler(...args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
WebBrowser wb = ...;
wb.themouseevent += myhandler; // equivalent to wb.themouseevent += this.myhandler;
use closures or custom objects to expose a handler from an object that will "know" the browser beforewards:
// inside or outside your Window/etc:
class MyHandlersWithSomeData
{
public WebBrowser browser;
public string someContextuaData;
public int otherData;
....
public void MyHandler(...args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
}
// inside your Window/etc:
WebBrowser wb = ...;
var smartHandler = new MyHandlersWithSomeData{ browser = wb, otherData = 10 };
wb.themouseevent += smartHandler.MyHandler; // note that handler is not from "this" anymore
edit: As you asked, a "simpler" approach would be to use lambdas and closures:
// inside your Window/etc:
private int otherData;
private void JustAMethodNotAHandler(WebBrowser browser, object sender, EventArgs args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
WebBrowser wb = ...;
wb.themouseevent += (sender, args) => JustAMethodNotAHandler(wb, sender, args);
However there is no magic. Under the hood, it does it almost exactly as the example above with an extra class, so called "closure". This class will store the reference to WebBrowser wb local variable and only thanks to that, when JustAMethodNotAHandler is later called, the wb is still available and passable to that method.
However, since we are now using lambdas ((blah)=>blah syntax) to quickly create the delegate, you must notice two very important things:
JustAMethodNotAHandler is not the handler, it is just a method. The anonymous function created by the lambda will be the actual handler
since the anonymous function is, well, anonymous, you will have a hard time if you ever want to unregister it later. Attempts like:
wb.themouseevent -= (sender, args) => JustAMethodNotAHandler(wb, sender, args);
will not work since each time that line is executed, a new handler is created, totally not equal to the one created with +=
I just tried to subscribe to WPF property change events using C++/CLI. I didn't expect this to get difficult.
First I tried to subscribe to a specific property of some window (IsMouseDirectlyOver) and finally succeeded with following code:
void MyClass::DependencyPropertyChanged(Object^ sender, DependencyPropertyChangedEventArgs args)
{
Debug::WriteLine("DependencyPropertyChanged: "+sender->ToString()+", "+args.Property->Name);
}
window->IsMouseDirectlyOverChanged += gcnew DependencyPropertyChangedEventHandler(this, &MyClass::DependencyPropertyChanged);
Then I tried to subscribe to any property changes of an object (which is most important to me because my final code must be able to handle property changes by property names). I totally failed on this.
I tried various things but nothing worked. I could not find any C++/CLI examples but according to documentation and C# examples the following seemed to be the most sensible code to me:
window->PropertyChanged += gcnew PropertyChangedEventHandler(this, &MyClass::PropertyChanged);
void MyClass::PropertyChanged(Object^ sender, PropertyChangedEventArgs^ args)
{
...
}
But the compiler tells me by error C2039 that 'PropertyChangedEvent' is no element of 'System::Windows::Window'.
How can I achieve what I want?
Al mentioned in the comments, your code doesn't work, because there is no PropertyChanged event on Window, it's as simple as that.
What you can do instead is to override the OnPropertyChanged() method, which is present on a Window. In your override, you can do anything you want, including raising PropertyChanged (don't forget to create that event first).
I had a look on the snoop sources. I modified it and wrote a very, very basic example that works:
String^ ownerPropertyName = "IsActive";
DependencyObject^ propertyOwner = window;
DependencyPropertyDescriptor^ ownerPropertyDescriptor = DependencyPropertyDescriptor::FromName(ownerPropertyName, propertyOwner->GetType(), propertyOwner->GetType());
DependencyProperty^ ownerProperty = ownerPropertyDescriptor->DependencyProperty;
Type^ ownerPropertyType = ownerProperty->PropertyType;
DependencyProperty^ myProperty = DependencyProperty::Register(ownerPropertyName, ownerPropertyType, GetType(), gcnew PropertyMetadata(gcnew PropertyChangedCallback(&MyClass::BoundPropertyChangedCallback)));
Binding^ myPropertyToOwnerPropertyBinding = gcnew Binding(ownerPropertyName);
myPropertyToOwnerPropertyBinding->Mode = BindingMode::OneWay;
myPropertyToOwnerPropertyBinding->Source = propertyOwner;
BindingOperations::SetBinding(this, myProperty, myPropertyToOwnerPropertyBinding);
And:
static void BoundPropertyChangedCallback(DependencyObject^ me, DependencyPropertyChangedEventArgs args)
{
Debug::WriteLine("BoundPropertyChangedCallback: "+args.OldValue+", "+args.NewValue+", "+args.Property->Name);
}
Looks pretty complicated to me. I have no idea if that binding stuff is really necessary. In fact this can even subscribe to properties that do not have events (like IsMouseOver) and can operate on objects that do not implement INotifyPropertyChanged (like Window). And it does not need any switch/case for properties.
The class PropertyDescriptor (or the derived DependencyPropertyDescriptor) provides a mechanism to add a property change handler by their AddValueChanged method:
DependencyPropertyDescriptor^ propertyDescriptor = DependencyPropertyDescriptor::FromName(
"ActualWidth", component->GetType(), component->GetType());
propertyDescriptor->AddValueChanged(component, gcnew EventHandler(ActualWidthChanged));
...
static void ActualWidthChanged(Object^ component, EventArgs^ e)
{
...
}
Unfortunately the handler doesn't get passed the changed property, so i guess you would have to add different handlers for all properties you want to monitor.
EDIT: You might implement something like the code shown below that uses an anonymous delegate to pass the property name to an appropriate handler. Note however that this is C#, and to my understanding this can't be done in C++/CLI, since there it does not support managed lambdas. Mayby you could wrap a helper class like this in a separate assembly and use it from your C++/CLI code.
public delegate void PropertyChangedHandler(object component, string propertyName);
public static class DependencyPropertyDescriptorExt
{
public static void AddPropertyChangedHandler(
this object component, string propertyName, PropertyChangedHandler handler)
{
var propertyDescriptor = DependencyPropertyDescriptor.FromName(
propertyName, component.GetType(), component.GetType());
propertyDescriptor.AddValueChanged(component, (o, e) => handler(o, propertyName));
}
}
Now you could write and use such a PropertyChangedHandler like this:
this.AddPropertyChangedHandler("ActualHeight", PropertyChanged);
...
private void PropertyChanged(object component, string propertyName)
{
...
}
I've been trying to google this but have been unable to find a solution that works for me.
I have a DataGrid that is displaying some info from a SQL table that the client dosn't know about.
The client just sends a request to the server and gets a List<SomeClass> as a response that it then displays in a DataGrid.
I need to detect when the user makes change to a row and I need the new values that the user entered.
Currently I'm using RowEditEnding event. And the method that handles this event can then:
private void editRowEventHandler(object sender, DataGridRowEditEndingEventArgs e)
{
SomeClass sClass = e.Row.DataContext as SomeClass;
// Send sClass to the server to be saved in the database...
}
This gives me the row that was being edited. But it gives me the row before the changes, and I'm unable to figure out how to get the row after the changes happen.
Is there anyone here that knows how I can do this or can point me in a direction where I might be able to find out?
See the discussion here, to avoid reading out cell-by-cell.
private void OnRowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (e.EditAction == DataGridEditAction.Commit) {
ListCollectionView view = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource) as ListCollectionView;
if (view.IsAddingNew || view.IsEditingItem) {
this.Dispatcher.BeginInvoke(new DispatcherOperationCallback(param =>
{
// This callback will be called after the CollectionView
// has pushed the changes back to the DataGrid.ItemSource.
// Write code here to save the data to the database.
return null;
}), DispatcherPriority.Background, new object[] { null });
}
}
}
In your case, you are trying to detect the change in object. It comes down to the properties of the SomeClass, thus you need to focus on "Cell" instead of "Row"
Assuming your datagrid is resultGrid, i come up with the below code:
resultGrid.CellEditEnding += resultGrid_CellEditEnding;
void resultGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var yourClassInstance = e.EditingElement.DataContext;
var editingTextBox = e.EditingElement as TextBox;
var newValue = editingTextBox.Text;
}
the "e" also contains information about Row and Column of the Cell. Thus you will know which editor the cell is using. In this case, i assume that it is a textbox.
Hope it help.
I'm using the CAG and I've got some issues using the TabControl region. I worked out that by marking the view (and NOT the PresentationModel) as IActiveAware I can get an event when the view is activated/deactivated. That works well when the composite is simple and the TabItem is the view.
However, in my case I've got a composite inside the TabItem. It can listen to activation events but I'd like to propagate these events to its children so that they can react to them. Is there a way of doing that? I had a look at the RegionContext but it doesn't seem to work in my case (or maybe I'm doing it wrong).
Could it be that I'm missing out on something and an attached dependency or something else would solve my issue?
I decided to use the RegionContext to propagate the IsActive state within the region.
Set it up as:
Regions:RegionManager.RegionContext="{Binding Path=IsActive, Mode=TwoWay}"
on my tab view (which is IActiveAware). Then in the child view I can listen to changes:
RegionContext.GetObservableContext((DependencyObject)View).PropertyChanged += new PropertyChangedEventHandler(VehiclesPresentationModel_PropertyChanged);
private void VehiclesPresentationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
IsActive = (bool)RegionContext.GetObservableContext((DependencyObject)View).Value;
}
}
The remaining issue was that the reverse would work. Setting IsActive on the tab view doesn't active the tab :(
I added a custom behavior and now it works. The custom bahavior is like:
public class RegionReverseActiveAwareBehavior : RegionBehavior
{
public const string BehaviorKey = "RegionReverseActiveAwareBehavior";
protected override void OnAttach()
{
Region.Views.CollectionChanged += new NotifyCollectionChangedEventHandler(Views_CollectionChanged);
}
private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
IActiveAware activeAwareItem = item as IActiveAware;
if (activeAwareItem != null)
{
activeAwareItem.IsActiveChanged += new EventHandler(activeAwareItem_IsActiveChanged);
}
}
}
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
IActiveAware activeAwareItem = item as IActiveAware;
if (activeAwareItem != null)
{
activeAwareItem.IsActiveChanged -= new EventHandler(activeAwareItem_IsActiveChanged);
}
}
}
}
private void activeAwareItem_IsActiveChanged(object sender, EventArgs e)
{
IActiveAware activeAware = sender as IActiveAware;
if (activeAware != null &&
activeAware.IsActive)
{
Region.Activate(activeAware);
}
}
}
And then I set it up on the TabControl with:
RegionManager.GetObservableRegion(tabRegion).PropertyChanged +=
(sender, args) =>
{
if (args.PropertyName == "Value")
{
IRegion region = RegionManager.GetObservableRegion(tabRegion).Value;
region.Behaviors.Add(RegionReverseActiveAwareBehavior.BehaviorKey, new RegionReverseActiveAwareBehavior());
}
};
Hope that solves someone else's issue. Or maybe there's an easier way that I'm missing.
Have you looked at Prism EventAggregator? This can be implemented as some sort of MessageBus or Mediator...
You can Puplish events and everyone who needs be interested can subscribe to it...
If you look in the prism samples you find an implementation or something in the docs...
The Prism EventAggregator (EA) object allows you to publish events and subscribe to them through the EA object. This can be used with a single publisher and 0, 1 or many subscribers. I generally use the EA when I need to communicate between different parts of an application that are not tied together. For example, a menu item in the shell of a Prism application may need to invoke another view in a different module. The EA allows you to do this via pub/sub. However if a screen needs to make something happen on its own self, this ifs often better suited for the Command object.
How are you instrumenting your UI's? In the past I've read that people have instrumented their user interfaces, but what I haven't found is examples or tips on how to instrument a UI.
By instrumenting, I mean collecting data regarding usage and performance of the system. A MSDN article on Instrumentation is http://msdn.microsoft.com/en-us/library/x5952w0c.aspx. I would like to capture which buttons users click on, what keyboard shortucts they use, what terms they use to search, etc.
How are you instrumenting your UI?
What format are you storing the instrumentation?
How are you processing the instrumented data?
How are you keeping your UI code clean with this instrumentation logic?
Specifically, I am implementing my UI in WPF, so this will provide extra challenges compared to instrumenting a web-based application. (i.e. need to transfer the instrumented data back to a central location, etc). That said, I feel the technology may provide an easier implementation of instrumentation via concepts like attached properties.
Have you instrumented a WPF application? Do you have any tips on how this can be achieved?
Edit: The following blog post presents an interesting solution: Pixel-In-Gene Blog: Techniques for UI Auditing on WPF apps
Here is an example of how I use a simple events manager to hook on to the UI events and extract key information of the events, such as name and type of UI element, name of event and the parent window's type name. For lists I also extract the selected item.
This solution only listens for clicks of controls derived from ButtonBase (Button, ToggleButton, ...) and selection changes in controls derived from Selector (ListBox, TabControl, ...). It should be easy to extend to other types of UI elements or to achieve a more fine-grained solution. The solution is inspired of Brad Leach's answer.
public class UserInteractionEventsManager
{
public delegate void ButtonClickedHandler(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowName);
public delegate void SelectorSelectedHandler(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowName, object selectedObject);
public event ButtonClickedHandler ButtonClicked;
public event SelectorSelectedHandler SelectorSelected;
public UserInteractionEventsManager()
{
EventManager.RegisterClassHandler(typeof(ButtonBase), ButtonBase.ClickEvent, new RoutedEventHandler(HandleButtonClicked));
EventManager.RegisterClassHandler(typeof(Selector), Selector.SelectionChangedEvent, new RoutedEventHandler(HandleSelectorSelected));
}
#region Handling events
private void HandleSelectorSelected(object sender, RoutedEventArgs e)
{
// Avoid multiple events due to bubbling. Example: A ListBox inside a TabControl will cause both to send the SelectionChangedEvent.
if (sender != e.OriginalSource) return;
var args = e as SelectionChangedEventArgs;
if (args == null || args.AddedItems.Count == 0) return;
var element = sender as FrameworkElement;
if (element == null) return;
string senderName = GetSenderName(element);
string parentWindowName = GetParentWindowTypeName(sender);
DateTime time = DateTime.Now;
string eventName = e.RoutedEvent.Name;
string senderTypeName = sender.GetType().Name;
string selectedItemText = args.AddedItems.Count > 0 ? args.AddedItems[0].ToString() : "<no selected items>";
if (SelectorSelected != null)
SelectorSelected(time, eventName, senderName, senderTypeName, parentWindowName, selectedItemText);
}
private void HandleButtonClicked(object sender, RoutedEventArgs e)
{
var element = sender as FrameworkElement;
if (element == null) return;
string parentWindowName = GetParentWindowTypeName(sender);
DateTime time = DateTime.Now;
string eventName = e.RoutedEvent.Name;
string senderTypeName = sender.GetType().Name;
string senderName = GetSenderName(element);
if (ButtonClicked != null)
ButtonClicked(time, eventName, senderName, senderTypeName, parentWindowName);
}
#endregion
#region Private helpers
private static string GetSenderName(FrameworkElement element)
{
return !String.IsNullOrEmpty(element.Name) ? element.Name : "<no item name>";
}
private static string GetParentWindowTypeName(object sender)
{
var parent = FindParent<Window>(sender as DependencyObject);
return parent != null ? parent.GetType().Name : "<no parent>";
}
private static T FindParent<T>(DependencyObject item) where T : class
{
if (item == null)
return default(T);
if (item is T)
return item as T;
DependencyObject parent = VisualTreeHelper.GetParent(item);
if (parent == null)
return default(T);
return FindParent<T>(parent);
}
#endregion
}
And to do the actual logging, I use log4net and created a separate logger named 'Interaction' to log user interaction. The class 'Log' here is simply my own static wrapper for log4net.
/// <summary>
/// The user interaction logger uses <see cref="UserInteractionEventsManager"/> to listen for events on GUI elements, such as buttons, list boxes, tab controls etc.
/// The events are then logged in a readable format using Log.Interaction.Info().
/// </summary>
public class UserInteractionLogger
{
private readonly UserInteractionEventsManager _events;
private bool _started;
/// <summary>
/// Create a user interaction logger. Remember to Start() it.
/// </summary>
public UserInteractionLogger()
{
_events = new UserInteractionEventsManager();
}
/// <summary>
/// Start logging user interaction events.
/// </summary>
public void Start()
{
if (_started) return;
_events.ButtonClicked += ButtonClicked;
_events.SelectorSelected += SelectorSelected;
_started = true;
}
/// <summary>
/// Stop logging user interaction events.
/// </summary>
public void Stop()
{
if (!_started) return;
_events.ButtonClicked -= ButtonClicked;
_events.SelectorSelected -= SelectorSelected;
_started = false;
}
private static void SelectorSelected(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowTypeName, object selectedObject)
{
Log.Interaction.Info("{0}.{1} by {2} in {3}. Selected: {4}", senderTypeName, eventName, senderName, parentWindowTypeName, selectedObject);
}
private static void ButtonClicked(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowTypeName)
{
Log.Interaction.Info("{0}.{1} by {2} in {3}", senderTypeName, eventName, senderName, parentWindowTypeName);
}
}
The output would then look something like this, omitting non-relevant log entries.
04/13 08:38:37.069 INFO Iact ToggleButton.Click by AnalysisButton in MyMainWindow
04/13 08:38:38.493 INFO Iact ListBox.SelectionChanged by ListView in MyMainWindow. Selected: Andreas Larsen
04/13 08:38:44.587 INFO Iact Button.Click by EditEntryButton in MyMainWindow
04/13 08:38:46.068 INFO Iact Button.Click by OkButton in EditEntryDialog
04/13 08:38:47.395 INFO Iact ToggleButton.Click by ExitButton in MyMainWindow
The following blog post gives quite a few good ideas for instrumenting a WPF application:
Techniques for UI Auditing on WPF apps.
You could consider log4net. It is a robust logging framework that exists in a single DLL. It is also done in a "non demanding" type mode so that if a critical process is going on, it won't log until resources are freed up a bit more.
You could easily setup a bunch of INFO level loggers and track all the user interaction you needed, and it wouldn't take a bug crash to send the file to yourself. You could also then log all your ERROR and FATAL code to seperate file that could easily be mailed to you for processing.
If you make use of WPF commands, each custom command could then log the Action taken. You can also log the way the command was initiated.
Perhaps the Microsoft UI Automation for WPF can help out ? Its a framework for automating your UI, perhaps it can be used to log stuff for you...
We use the Automation Framework for auto-testing our UI in WPF.
I have not yet developed using WPF.. But I would assume that its the same as most other applications in that you want to keep the UI code as light as possible.. A number of design patterns may be used in this such as the obvious MVC and Façade. I personally always try and keep the objects travelling between the UI and BL layers as light as possible, keeping them to primitives if I can.
This then helps me focus on improving the UI layer without the concerns of anything going on once I throw my (primitive) data back..
I hope I understood your question correctly, and sorry I cannot offer more contextual help with WPF.
Disclaimer: I work for the company that sells this product, not only that but I am a developer on this particular product :) .
If you are interested in a commercial product to provide this then Runtime Intelligence (a functional add on to Dotfuscator ) that injects usage tracking functionality into your .NET applications is available. We provide not only the actual implementation of the tracking functionality but the data collection, processing and reporting functionality as well.
There was recently a discussion on the Business of Software forum on this topic that I also posted in located here: http://discuss.joelonsoftware.com/default.asp?biz.5.680205.26 .
For a high level overview of our stuff see here: http://www.preemptive.com/runtime-intelligence-services.html .
In addition I am currently working on writing up some more technically oriented documentation as we realize that is an area we could definitely improve, please let me know if anyone is interested in being notified when I have completed it.