I'm building a chat application and I am parsing out links and adding them to the chatroom view with Hyperlinks. These Hyperlinks have the following event handler set to them:
void urlLink_Click(object sender, RoutedEventArgs e)
{
try
{
Hyperlink link = sender as Hyperlink;
this.chatUI.DisplayWebBrowser(link.NavigateUri);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Whether or not the event gets triggered seems to be random though. Some links will work as intended when clicked, while some links will not work. Some links work to start with but after more messages are received, they stop working. Anyone know what's the cause and how to solve this? This is how the Hyperlink control is being created:
newSpan = new Span();
Run urlRun = new Run();
urlRun.Text = urlMatches[i].Value;
Hyperlink urlLink = new Hyperlink();
urlLink.NavigateUri = new Uri(urlMatches[i].Value, UriKind.Absolute); // Add URI to the Hyperlink control
urlLink.Click += urlLink_Click; // Add event handler to control
urlLink.Inlines.Add(urlRun); // Add text to Hyperlink
I had the same issue. By some trial and error, I fixed it... by assigning a dummy empty command to the Hyperlink. Don't ask me to explain, I still haven't managed to understand how it could fix anything, but in my case it did.
First, declare a DummyCommand class:
/// <summary>
/// Workaround for the hyperlink click issue. What the hell is going on?
/// </summary>
public class DummyCommand : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
}
public event EventHandler CanExecuteChanged;
}
Then, when creating a Hyperlink, make sure to assign the DummyCommand to the Command property:
newSpan = new Span();
Run urlRun = new Run();
urlRun.Text = urlMatches[i].Value;
Hyperlink urlLink = new Hyperlink();
urlLink.NavigateUri = new Uri(urlMatches[i].Value, UriKind.Absolute); // Add URI to the Hyperlink control
urlLink.Click += urlLink_Click; // Add event handler to control
urlLink.Command = new DummyCommand(); // Workaround for the Click not been triggered
urlLink.Inlines.Add(urlRun); // Add text to Hyperlin
Then scratch your head a bit, and move on to something else.
Related
I'm trying to correctly load an image: testing right now against common errors (ie a file that is badly formatted). It is a currently a simple wpf application I use to test things.
public partial class MainWindow : Window
{
public MainWindow() {
var s = new BitmapImage();
var uri = new Uri("test.txt", UriKind.RelativeOrAbsolute); //test exists but is obviously no image data
DownloadImageListener dl = new DownloadImageListener(s);
s.DecodeFailed += (sender, e) =>
{
Console.WriteLine("event is performed as lambda");
};
s.BeginInit();
s.UriSource = uri;
s.EndInit();
Console.WriteLine(System.IO.File.Exists(uri.OriginalString)); //True!
Console.WriteLine(s.IsDownloading); //"False" - done loading!
Console.WriteLine(s.Width); //just to fail hard
}
}
class DownloadImageListener
{
private BitmapImage Img;
public DownloadImageListener(BitmapImage i) {
Img = i;
// Add "ListChanged" to the Changed event on "List".
Img.DecodeFailed += new EventHandler<ExceptionEventArgs>(ImageLoadFailed);
}
// This will be called whenever the list changes.
private void ImageLoadFailed(object sender, EventArgs e) {
Console.WriteLine("This is called when the loading failes");
}
public void Detach() {
// Detach the event and delete the list
Img.DecodeFailed -= new EventHandler<ExceptionEventArgs>(ImageLoadFailed);
Img = null;
}
}
The ImageLoadFailed method is never called (no line is printed nor does visual studio trigger the breakpoint I placed there). Am I doing something "wrong"? I believe I followed the tutorial provided by msdn?
EDIT:
To rule out all potential other errors, I've added above the "isdownloading" check
Console.WriteLine(System.IO.File.Exists(uri.OriginalString));
which shows "True"
I've also added a lambda as listener - as shown by this page.
EDIT 2:
Testing "all" events it seems that only the "changed" event fires (so the code to catch the events is apparently correct) - the rest of the events never fire. - Why is this?
You could simply set BitmapCacheOption.OnLoad to make WPF immediately load the image file, and get an exception when it can't be decoded:
var bitmap = new BitmapImage();
try
{
bitmap.BeginInit();
bitmap.UriSource = new Uri("test.txt", UriKind.RelativeOrAbsolute);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
DownloadFailed as it's name denotes will be executed only if the image can't be downloaded, and as you state in the comments it exists but it's not an image.
If you want to detect an error in the downloaded file then use the DecodeFailed event.
I want to capture 'Send' button event of outlook using UI Automation.
Right now i am able to get 'Focus Change Event' like whenever iam minimizing or maximizing the WINWORD window the the event is raised instead of that i want to get the event on Send button click.
private void SendButtonInvoke()
{
Process[] processes = Process.GetProcessesByName("WINWORD");
AutomationElement aeOutLook = null;
foreach (var item in processes)
{
aeOutLook = AutomationElement.FromHandle(item.MainWindowHandle);
}
//AutomationElement outlookelm = AutomationElement.FromHandle(processName.MainWindowHandle);
AutomationElement buttonAddInstance = aeOutLook.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "Send"));
if (buttonAddInstance == null)
{
MessageBox.Show("Add button instance not found");
}
else
{
AutomationPropertyChangedEventHandler ButtonEvent =
new AutomationPropertyChangedEventHandler(ButtonChecked_EventHandler);
//Attaching the EventHandler
Automation.AddAutomationPropertyChangedEventHandler(buttonAddInstance, TreeScope.Children,
ButtonEvent, AutomationElement.NameProperty);
}
}
private void ButtonChecked_EventHandler(object sender, AutomationEventArgs e)
{
AutomationElement ar = sender as AutomationElement;
MessageBox.Show("Button Clicked Sucessfully.");
}
You have to specifiy the EventHandler for the involved UIA Pattern. (For your case it's likely to be the InvokePattern):
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, AutomationElement buttonAddInstance ,TreeScope.Element, new AutomationEventHandler(OnStartInvoke));
private static void OnStartInvoke(object src, AutomationEventArgs e)
{
//logic
}
I wrote and tested the code below and it seems to work for me.
private void AddEmailSendEvent()
{
// Find the new email window
PropertyCondition newEmailWindowCondition = new PropertyCondition(AutomationElement.NameProperty, "Untitled - Message (HTML) ");
AutomationElement NewEmailWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, newEmailWindowCondition);
// Find the Send Button
PropertyCondition sendEmailButtonCondition = new PropertyCondition(AutomationElement.NameProperty, "Send");
AutomationElement sendButton = NewEmailWindow.FindFirst(TreeScope.Descendants, sendEmailButtonCondition);
// If supported, add the invoke event
if (sendButton.GetSupportedPatterns().Any(p => p.Equals(InvokePattern.Pattern)))
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, sendButton, TreeScope.Element, handler);
}
private void handler(object sender, AutomationEventArgs e)
{
// Do whatever is needed, for testing this just adds a message to my forms Main UI
AddMessage("Invoke event occured");
}
I should note that I'm using the .Net 4.0 automation libs. I've found the older ones don't always work the way I want them. I also tested this with Outlook 2013, and both outlook and the new email message were already open when I tested this. It doesn't handle waiting for them to appear.
Just so your aware, these events don't always work for all controls. Some custom controls are made in such a way the invoke events are not reported to the UI in a way the event can register. With that said, from my testing you should be able to use this method on the send button.
Invoking vs mouse clicks: Just to add a little more detail, the standard control causes the invoke event to fire when a user clicks it. "Invoke" is just the standard event fired on clickable controls. The only time a click wouldn't fire the same invoke is if the developer decided to intercept the click somehow and redirect it elsewhere. I've seen this a lot when people build there own custom controls.
If your not sure about whether a control using/firing the invoke event or not you can get use the Accessible Event Watcher to watch a control as you click it. You can get more information on the tool here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317979(v=vs.85).aspx
So I have 2 controls on my main form, a custom hexbox control and a richtextbox as in the picture below (It wouldnt let me post an image so will have to follow the link). What I would like to do is depending on where the user has clicked in the hexbox control, the rich textbox on the right will scroll to an associated line.
http://i.stack.imgur.com/8PfRt.jpg
The current issue I'm having is that the code to handle the hexbox click is contained in a separate class (hexbox.cs) and so I'm not able to then take the location of the click and scroll to the associated line in the richtextbox which is contained in the mainform class. I attempted to create a new instance of the mainform to access the richtextbox but obviously this results is the creation of a new richtexbox with none of the original content.
Heres the code in the hexbox class that deals with a mouse click if its any help:
void SetCaretPosition(Point p)
{
System.Diagnostics.Debug.WriteLine("SetCaretPosition()", "HexBox");
if (_byteProvider == null || _keyInterpreter == null)
return;
long pos = _bytePos;
int cp = _byteCharacterPos;
if(_recHex.Contains(p))
{
BytePositionInfo bpi = GetHexBytePositionInfo(p);
pos = bpi.Index;
cp = bpi.CharacterPosition;
SetPosition(pos, cp);
ActivateKeyInterpreter();
UpdateCaret();
Invalidate();
}
else if(_recStringView.Contains(p))
{
BytePositionInfo bpi = GetStringBytePositionInfo(p);
pos = bpi.Index;
cp = bpi.CharacterPosition;
SetPosition(pos, cp);
ActivateStringKeyInterpreter();
UpdateCaret();
Invalidate();
}
}
If I undersntand properly, this should help.
If you have access to hexbox class, you can expose event (MouseClick - or similar) - or even create your own with args prividig selected line - subscribe to this event in your Form.
Then when user click your form class'll be notified .
class HexBox : UserControl{
// ..
}
public class MyForm :Form{
public MyForm(){
HexBox hexBox = new HexBox();
Controls.Add(hexBox);
hexBox.MouseDown += (sender, args) =>{
// call your scroll to function
};
InitializeComponent();
}
}
I have a strange problem with devexpress AlertControl. I create an alertu using this code
AlertInfo alertInfo = new AlertInfo(caption, text);
AlertControl control = new AlertControl();
control.FormLocation = AlertFormLocation.BottomRight;
control.Show(null,alertInfo);
this code is placed in backgroundWorker_DoWork function and it is supposed to display alerts from time to time. The problem is that alerts are not shown. I can see that show method is invoked however alerts are not shown.
Acording to documentation is I pass null as a parametr of Show function , notification should be shown on main monitor.
What can I do to make it work ?
Considering you're using a worker, I guess it's a thread problem. Try wrapping your code inside an Action object:
Action action = () =>
{
AlertControl control = new AlertControl();
control.FormLocation = AlertFormLocation.BottomRight;
control.Show(this, alertInfo); // "this" being a Form
};
this.Invoke(action);
I use a similar code inside a form with good results and once did a similar code using an AlertControl too.
Your AlertControl need a Parent Control.
AlertControl control = new AlertControl();
control.FormLocation = AlertFormLocation.BottomRight;
control.Show(MyForm,alertInfo); //replace null with a Form/Control instance
You call the Show method with a null paramater - where you should have use an instance of a Form/Control
Don't know anything about the devexpress controls, but maybe you have to show the alert from the main thread via invoke methode?
using DevExpress.XtraBars.Alerter;
// Create a regular custom button.
AlertButton btn1 = new AlertButton(Image.FromFile(#"c:\folder-16x16.png"));
btn1.Hint = "Open file";
btn1.Name = "buttonOpen";
// Create a check custom button.
AlertButton btn2 = new AlertButton(Image.FromFile(#"c:\clock-16x16.png"));
btn2.Style = AlertButtonStyle.CheckButton;
btn2.Down = true;
btn2.Hint = "Alert On";
btn2.Name = "buttonAlert";
// Add buttons to the AlertControl and subscribe to the events to process button clicks
alertControl1.Buttons.Add(btn1);
alertControl1.Buttons.Add(btn2);
alertControl1.ButtonClick += new AlertButtonClickEventHandler(alertControl1_ButtonClick);
alertControl1.ButtonDownChanged +=
new AlertButtonDownChangedEventHandler(alertControl1_ButtonDownChanged);
// Show a sample alert window.
AlertInfo info = new AlertInfo("New Window", "Text");
alertControl1.Show(this, info);
void alertControl1_ButtonDownChanged(object sender,
AlertButtonDownChangedEventArgs e) {
if (e.ButtonName == "buttonOpen") {
//...
}
}
void alertControl1_ButtonClick(object sender, AlertButtonClickEventArgs e) {
if (e.ButtonName == "buttonAlert") {
//...
}
}
ref:https://documentation.devexpress.com/#WindowsForms/clsDevExpressXtraBarsAlerterAlertControltopic
I create an instance of IE outside my program, which the program finds and attaches to correctly. I set up my event handler and tell the program to advance to the login screen. The DocumentCompleted handle is supposed to fire when the web page is completely loaded, but mine seems to be firing before the new page has appeared.. The handle only fires once (meaning there is only one frame?).
This code executes fine if I modify it to work straight from the login page also.. Am I doing something wrong? Thanks for any assistance :)
Process.Start(#"IESpecial.exe");
SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
while (true)
{
foreach (SHDocVw.WebBrowser ie in allBrowsers)
{
if (ie.LocationURL == "http://website/home.asp")
{
loggingIn = true;
webBrowser = ie;
webBrowser.DocumentComplete += new SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(webBrowser1_DocumentCompleted);
webBrowser.Navigate("http://website/logon.asp");
return;
}
}
Thread.Sleep(10);
}
}
private void webBrowser1_DocumentCompleted(object pDisp, ref object URL)
{
//we are attempting to log in
if (loggingIn)
{
mshtml.HTMLDocumentClass doc = (mshtml.HTMLDocumentClass)webBrowser.Document;
mshtml.HTMLWindow2 window = (mshtml.HTMLWindow2)doc.IHTMLDocument2_parentWindow;
doc.getElementById("Username").setAttribute("value", "MLAPAGLIA");
doc.getElementById("Password").setAttribute("value", "PASSWORD");
window.execScript("SubmitAction()", "javascript");
loggingIn = false;
return;
}