Prevent RepositoryItemSearchLookUpEdit when Popup is Open When CloseUpKey.Key is pressed - winforms

I use a RepositoryItemSearchLookUpEdit. its CloseUpKey property is set to space
result.CloseUpKey = new DevExpress.Utils.KeyShortcut(System.Windows.Forms.Keys.Space);
I want to use this shortcut only for open popup and not for closing popup.
How can I achieve this?
UPDATE------------------------
First I create an RepositoryItemSearchLookUpEdit object
var result = new RepositoryItemSearchLookUpEdit();
result.CloseUpKey = new DevExpress.Utils.KeyShortcut(System.Windows.Forms.Keys.Space);
result.KeyDown += repositoryItemLookUpEdit_KeyDown;
result.CloseUp += repositoryItemLookUpEdit_CloseUp;
result.QueryCloseUp += repositoryItemLookUpEdit_QueryCloseUp;
private void repositoryItemLookUpEdit_QueryCloseUp(object sender, System.ComponentModel.CancelEventArgs e)
{
var edit = sender as SearchLookUpEdit;
KeyEventArgs k = new KeyEventArgs(edit.Properties.CloseUpKey.Key);
AttachKeyPressEvent(k);
if (k.KeyCode == edit.Properties.CloseUpKey.Key)
e.Cancel = true;
}
And pass it to a grid column:
grdListView.Columns["yyy"].ColumnEdit = result
How can I achieve that with these events, without creating a descendant SearchLookUpEdit

UPDATED:
The problem is that CloseUp event (where you could get the necessary info about the closeup key) occurs after the QueryCloseUp event (where you could precent the closing up event). Also the KeyPress, KeyDown and KeyUp events seem also NOT to occur when the QueryCloseUp occurs, as a result they couldn't be overridden. So I tried this, I created a custom KeyEventHandler and triggered him during QueryCloseUp event in order to get the necessary info of what key was pressed and cancel the event if the close key event was the one. Here is my codeTry it to see if it suits you
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Here you can add your grid control as you have created
DataTable dt = new DataTable();
dt.Columns.Add("ID"); //use your own names and types
gridControl1.DataSource = dt;
var result = new RepositoryItemSearchLookUpEdit();
result.CloseUpKey = new DevExpress.Utils.KeyShortcut(System.Windows.Forms.Keys.Space);
result.QueryCloseUp += new CancelEventHandler(repositoryItemLookUpEdit_QueryCloseUp);
((gridControl1.MainView as GridView).Columns["ID"] as GridColumn).ColumnEdit = result;
}
private static readonly object myQueryCloseUp = new object();
public event KeyEventHandler MyQueryCloseUp
{
add { Events.AddHandler(myQueryCloseUp, value); }
remove { Events.RemoveHandler(myQueryCloseUp, value); }
}
protected virtual void AttachKeyPressEvent(KeyEventArgs e)
{
KeyEventHandler handler = (KeyEventHandler)Events[myQueryCloseUp];
if (handler != null)
handler(this, e);
}
//Here you add your own Handler implementation
public void repositoryItemLookUpEdit_QueryCloseUp(object sender, CancelEventArgs e)
{
KeyEventArgs k = new KeyEventArgs((sender as SearchLookUpEdit).Properties.CloseUpKey.Key);
AttachKeyPressEvent(k);
if (k.KeyCode == (sender as SearchLookUpEdit).Properties.CloseUpKey.Key)
e.Cancel = true;
}
}

Related

WPF Cannot unsubscribe from a RoutedEvent, not working. After unsubscribing it continues firing

I have an WPF User control in which I create a RoutedEventHandler. I want to raise an event notifying every time its height changes:
Wpfusercontrol.designer.cs:
public partial class Wpfusercontrol: System.Windows.Controls.UserControl
{
public static readonly RoutedEvent HeightChangedEvent = EventManager.RegisterRoutedEvent(
"HeightChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Wpfusercontrol));
public event RoutedEventHandler HeightChanged
{
add { AddHandler(HeightChangedEvent, value); }
remove { RemoveHandler(HeightChangedEvent, value); }
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.HeightChanged && HeightChangedEvent != null)
{
RaiseEvent(new RoutedEventArgs(HeightChangedEvent));
}
}
}
Then this WPF user control is hosted in an ElementHost
WindowsFormsHostControl.Designer.cs:
partial class WindowsFormsHostControl
{
private void InitializeComponent()
{
this.ElementHostFormControl = new System.Windows.Forms.Integration.ElementHost();
this.Wpfusercontrol= new Wpfusercontrol();
this.SuspendLayout();
//
// ElementHostFormControl
//
this.ElementHostFormControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.ElementHostFormControl.Location = new System.Drawing.Point(0, 0);
this.ElementHostFormControl.Margin = new System.Windows.Forms.Padding(2);
this.ElementHostFormControl.Name = "ElementHostFormControl";
this.ElementHostFormControl.Size = new System.Drawing.Size(75, 78);
this.ElementHostFormControl.TabIndex = 0;
this.ElementHostFormControl.Child = this.Wpfusercontrol;
//
// WindowsFormsHostControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.ElementHostFormControl);
this.Margin = new System.Windows.Forms.Padding(2);
this.Name = "WindowsFormsHostControl";
this.Size = new System.Drawing.Size(75, 78);
this.ResumeLayout(false);
}
private System.Windows.Forms.Integration.ElementHost ElementHostFormControl;
private Wpfusercontrol Wpfusercontrol;
}
WindowsFormsHostControl.cs:
public partial class WindowsFormsHostControl: System.Windows.Forms.UserControl
{
private RoutedEventHandler heightChangedEventHandler;
public WindowsFormsHostControl()
{
InitializeComponent();
}
public WindowsFormsHostControl(RoutedEventHandler heightChangedEventHandler) : this()
{
this.heightChangedEventHandler = heightChangedEventHandler;
this.Wpfusercontrol.HeightChanged += this.heightChangedEventHandler;
}
public void SubscribeHeightChanged()
{
this.Wpfusercontrol.HeightChanged += this.heightChangedEventHandler;
}
public void UnsubscribeHeightChanged()
{
this.Wpfusercontrol.HeightChanged -= this.heightChangedEventHandler;
}
}
This WindowsFormsHostControl is embedded within an UI object called custom task pane which is kind of UI container for VSTO Outlook Add-ins. This custom task pane has a button to resize its height but it does not provide an event to catch it. So when you resize the height of that custom task pane, the height of the wpf user control changes as well, so through the routed event in the wpf user control I know when the custom task pane is resized and I catch the event.
Now from one class in my VSTO Outlook Add-in application (which in fact is a winforms app), I perform below things:
private WindowsFormsHostControl windowsFormsHostControl = null;
this.windowsFormsHostControl = new WindowsFormsHostControl(this.WpfUserControl_HeightChanged);
System.Windows.Fomrs.Timer t;
private void WpfUserControl_HeightChanged(object sender, System.Windows.RoutedEventArgs e)
{
// Dome some stuff
...
t = new System.Windows.Fomrs.Timer();
t.Tick += new EventHandler(Update);
t.Interval = 100;
t.Enable = true;
}
private void Update(object sender, EventArgs e)
{
// Some more stuf....
....
// In below lines I update the height of the custom task pane (VSTO Outlook UI object) which in turn causes the WPF user control to resize its height as well. So then, I am trying to unsubscribe from the wpf routed event, then update the height for custom task pane, and finally subscribe again to the wpf routed event. I do this to prevent routed event in wpf user control fires again.
this.windowsFormsHostControl.UnsubscribeHeightChanged();
// here I update the height for custom task pane
this.windowsFormsHostControl.SubscribeHeightChanged();
}
The problem is that it looks like the line:
this.windowsFormsHostControl.UnsubscribeHeightChanged();
is not working because the routed event in the wpf user control continues raising each time I execute the line of code between UnsubscribeHeightChanged and SubscribeHeightChanged.
So what am i doing wrong?

How to create user define (new) event for user control in WPF ?one small example

I have one UserControl in which I am using a Canvas, and in that Canvas one Rectangle. I want to create a click event for that user control (Canvas and Rectangle) which I then want to use in the main window.
The question is: I want to create a new click event for the UserControl. How to do it? Kindly show little example or the code.
A brief example on how to expose an event from the UserControl that the main window can register:
In your UserControl:
1 . Add the following declaration:
public event EventHandler UserControlClicked;
2 . In your UserControl_Clicked event raise the event like this:
private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (UserControlClicked != null)
{
UserControlClicked(this, EventArgs.Empty);
}
}
In your MainWindow:
Your usercontrol will now have a UserControlClicked event which you can register to:
<local:UserControl1 x:Name="UC" UserControlClicked="UC_OnUserControlClicked" />
i find this easier for passing value to handler:
public event Action<string> onUserCodeFetched;
private void btnEnterClicked(object sender, RoutedEventArgs e)
{
onUserCodeFetched(PersonellCode.Text);
PersonellCode.Text = "";
}
It's an old question, but I also found useful to bypass the event using a property-like custom event as in here. You can use a general EventHandler or you can be more specific (RoutedEventHandler, MouseButtonEventHandler, etc) to avoid later casts. For instance, to bypass a click event, you could write in your custom control class:
public readonly object objectLock = new object();
public event RoutedEventHandler CustomClick
{
add{ lock (objectLock) { myClickableInnerControl.Click += value;}}
remove {lock (objectLock) { myClickableInnerControl.Click -= value; }}
}
and for a PreviewMouseDown event, it would be something like:
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock) { myInnerControl.PreviewMouseDown += value;}}
remove {lock (objectLock) { myInnerControl.PreviewMouseDown -= value; }}
}
Where myInnerControl would be your canvas in this case.
Then you can initialize the event from xaml as
<local:myClickableControl x:Name="ClickCtrl1" CustomClick="ClickCtrl1_CustomClick" />
or
<local:myCustomControl x:Name="CustomCtrl1" CustomPreviewMouseDown="CustomCtrl1_CustomPreviewMouseDown" />
And from code behind:
ClickCtrl1.CustomClick+=ClickCtrl1_CustomClick;
or
CustomCtrl1.CustomPreviewMouseDown+=CustomCtrl1_CustomPreviewMouseDown;
You can also subscribe your callback to several inner controls events (being careful when they overlap as some events like previewMouseDown are not only fired by the front control but also by the controls underneath).
public readonly object objectLock = new object();
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add{ lock (objectLock)
{
myInnerControl1.PreviewMouseDown += value;
myInnerControl2.PreviewMouseDown += value;
}}
remove {lock (objectLock)
{
myInnerControl1.PreviewMouseDown -= value;
myInnerControl2.PreviewMouseDown -= value;
}}
}
(If the inner controls partially overlap, you can use the corresponding eventArgs Handled property in your callback method to avoid repetitions)
Finally, you can add a layer of control to the event fired by your inner control:
bool MousePreviewDownUsed = false;
event MouseButtonEventHandler _myPreviewMouseDownEvent = null;
public event MouseButtonEventHandler CustomPreviewMouseDown
{
add
{
lock (objectLock)
{
_myPreviewMouseDownEvent += value;
if (value != null && !MousePreviewDownUsed)
{
myInnerControl.PreviewMouseDown += myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = true;
}
}
}
remove
{
lock (objectLock)
{
if (_myPreviewMouseDownEvent != null)
{
_myPreviewMouseDownEvent -= value;
if ((_myPreviewMouseDownEvent == null ||
_myPreviewMouseDownEvent.GetInvocationList().Length == 0)
&& MousePreviewDownUsed)
{
_myPreviewMouseDownEvent = null;
myInnerControl.PreviewMouseDown -= myInnerControl_PreviewMouseDown;
MousePreviewDownUsed = false;
}
}
}
}
}
private void myInnerControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// Do some previous operations or control whether the event must be broadcasted
_myPreviewMouseDownEvent?.Invoke(sender, e);
}
This event is initialized from xaml or code behind the same way as before.

How to Raise DragDelta event on Thumb

As you can see below, I want to start moving when the component visibility changes.
because otherwise I need the user to click again to start the movement, and that is bad in terms of usability for my application.
public MoveILayoutControl()
{
InitializeComponent();
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(MoveILayoutControl_IsVisibleChanged);
this.moveThumb.DragDelta += new DragDeltaEventHandler(MoveThumb_DragDelta);
}
void MoveILayoutControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.IsVisible)
{
// Raise Drag Event !?
}
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var myData = DataContext as ILayoutVisual;
if (myData != null)
{
Point dragDelta = new Point(e.HorizontalChange, e.VerticalChange);
if (myData.Rotation != 0)
{
Matrix toCalculate = ((this.Parent as FrameworkElement).RenderTransform).Value;
if (toCalculate != null)
{
dragDelta = toCalculate.Transform(dragDelta);
}
}
myData.X += dragDelta.X;
myData.Y += dragDelta.Y;
}
}
I believe the only way is using reflection to change the internal values ​​of the thumb. Changing the property "IsDragging" (not tested).
I looked up the source code of Thumb and I think a better way is to simulate a MouseLeftButtonEvent on the thumb:
var evt = new MouseButtonEventArgs(mouseDevice, timestamp, MouseButton.Left)
{
RoutedEvent = UIElement.MouseLeftButtonDownEvent
};
thumb.RaiseEvent(evt);

How to create and use WebBrowser in background thread?

How can I create System.Windows.Forms.WebBrowser in background STA thread? I try use some code like this:
var tr = new Thread(wbThread);
tr.SetApartmentState(ApartmentState.STA);
tr.Start();
private void wbThread()
{
CWebBrowser browser = new CWebBrowser();
var text = browser.Navigate("http://site.com", CWebBrowser.EventType.loadCompleted).Body.InnerHtml;
}
CWebBrowser - custom class, wich delegate System.Windows.Forms.WebBrowser object Navigate method and wait until page completed loads. The problem is LoadCompleted event on System.Windows.Forms.WebBrowser object never raises. I found some solution here, but it does not work (can't find method Application.Run() on my WPF app).
public class CWebBrowser : ContentControl
{
public readonly System.Windows.Forms.WebBrowser innerWebBrowser;
private readonly AutoResetEvent loadCompletedEvent;
private readonly AutoResetEvent navigatedEvent;
public enum EventType
{
navigated, loadCompleted
}
public CWebBrowser()
{
innerWebBrowser = new System.Windows.Forms.WebBrowser();
loadCompletedEvent = new AutoResetEvent(false);
navigatedEvent = new AutoResetEvent(false);
System.Windows.Forms.Integration.WindowsFormsHost host = new System.Windows.Forms.Integration.WindowsFormsHost();
host.Child = innerWebBrowser;
Content = host;
innerWebBrowser.DocumentCompleted +=new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(innerWebBrowser_DocumentCompleted);
innerWebBrowser.Navigated += new System.Windows.Forms.WebBrowserNavigatedEventHandler(innerWebBrowser_Navigated);
}
void innerWebBrowser_Navigated(object sender, System.Windows.Forms.WebBrowserNavigatedEventArgs e)
{
navigatedEvent.Set();
}
void innerWebBrowser_DocumentCompleted(object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs e)
{
if (((sender as System.Windows.Forms.WebBrowser).ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete) || innerWebBrowser.IsBusy)
return;
var doc = innerWebBrowser.Document;
loadCompletedEvent.Set();
}
public System.Windows.Forms.HtmlDocument Navigate(string url, EventType etype)
{
if (etype == EventType.loadCompleted)
loadCompletedEvent.Reset();
else if (etype == EventType.navigated)
navigatedEvent.Reset();
innerWebBrowser.Navigate(url);
if (etype == EventType.loadCompleted)
loadCompletedEvent.WaitOne();
else if (etype == EventType.navigated)
navigatedEvent.WaitOne();
System.Windows.Forms.HtmlDocument doc = null;
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, new Action(
delegate
{
doc = innerWebBrowser.Document;
}));
return doc;
}
}
Thansk for all advices and sorry for my bad english :o(
Why don't you use the default WebBrowser control like this?
public MainPage()
{
InitializeComponent();
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(startNavigate);
}
void startNavigate()
{
WebBrowser wb = new WebBrowser();
wb.LoadCompleted += new LoadCompletedEventHandler(wb_LoadCompleted);
wb.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(wb_Navigated);
wb.Navigate(new Uri("http://www.google.com"));
}
void wb_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
// e.Content
}
void wb_LoadCompleted(object sender, NavigationEventArgs e)
{
// e.Content when the document finished loading.
}
Edit: You are using old System.Windows.Forms.WebBrowser control, instead System.Windows.Controls.WebBrowser which is part of WPF.

Silverlight Datagrid Refresh

So I have a datagrid in Silverlight that is bound to a WCF that populates a list of class. I basically a pass a parameter to a Linq query. When I do a second query I get double the results, a third triple and so forth. What can I do to make it so when I send a call out to the service that I only get one set of results. I have attached my code in case it helps anyone.
private void button1_Click(object sender, RoutedEventArgs e)
{
dgOrder.ItemsSource = null;
Uri address = new Uri(Application.Current.Host.Source, "../Services/Service1.svc");
//var client = new Services.dataserviceClient("CustomBinding_dataservice", address.AbsoluteUri);
var client = new ServiceReference2.Service1Client("CustomBinding_Service1", address.AbsolutePath);
client.GetOrderCompleted += (s, ea) =>
{
dgOrder.AutoGenerateColumns = false;
//dgOrder.ColumnWidth.Value = 100;
dgOrder.Columns.Add(CreateTextColumn("SKU", "SKU"));
dgOrder.Columns.Add(CreateTextColumn("productname", "Product Name"));
dgOrder.Columns.Add(CreateTextColumn("itemnumber", "Item Number"));
dgOrder.Columns.Add(CreateTextColumn("cost", "Cost"));
dgOrder.Columns.Add(CreateTextColumn("asin", "ASIN"));
dgOrder.Columns.Add(CreateTextColumn("pendingorder", "Rank"));
dgOrder.Columns.Add(CreateTextColumn("rank", "Node"));
//dgOrder.Columns.Add(CreateTextColumn("w4", "AMZN"));
dgOrder.Columns.Add(CreateTextColumn("amazon", "AMZN"));
dgOrder.Columns.Add(CreateTextColumn("ourprice", "OurPrice"));
dgOrder.Columns.Add(CreateTextColumn("bbprice", "BuyBox"));
dgOrder.Columns.Add(CreateTextColumn("afner", "AFN"));
dgOrder.Columns.Add(CreateTextColumn("quantity", "INV"));
dgOrder.Columns.Add(CreateTextColumn("w4", "W4"));
dgOrder.Columns.Add(CreateTextColumn("w3", "W3"));
dgOrder.Columns.Add(CreateTextColumn("w2", "W2"));
dgOrder.Columns.Add(CreateTextColumn("w1", "W1"));
dgOrder.Columns.Add(CreateTextColumn("order", "Order"));
dgOrder.Columns.Add(CreateTextColumn("total", "Total"));
dgOrder.Columns.Add(CreateTextColumn("profit", "Profit"));
dgOrder.Columns.Add(CreateTextColumn("percent", "Percent"));
dgOrder.Columns.Add(CreateHyperlink("asin"));
dgOrder.ItemsSource = ea.Result;
Original = ea.Result;
};
client.GetOrderAsync(txtCompany.Text);
}
The problem is , you are creating a new(duplicate) event handler every time you press the Button. Due to having an extra event for each button pres you do, you get extra sets of data. You need to create your Event.Completed method outside the Button.Cliked event.
To clarify:
public partial class NewPage : Page
{
Uri address = new Uri(Application.Current.Host.Source, "../Services/Service1.svc");
ServiceReference2.Service1Client client = new ServiceReference2.Service1Client("CustomBinding_Service1", address.AbsolutePath);
public NewPage()
{
client.GetOrderCompleted += (s, ea) =>
{
//YOUR CODE
};
}
private void button1_Click(object sender, RoutedEventArgs e)
{
dgOrder.ItemsSource = null;
client.GetOrderAsync(txtCompany.Text);
}
}

Resources