I'm surprised I couldn't find this already answered; it seems like it would be a common problem. This is related to another question I posted today. What I am trying to do is edit some complex properties of a custom control using a non-modal editor dialog which is popped up by a ControlDesigner. There is a longer explanation in the other thread of how (and why) I am doing that, but for this post, I just have a simple question: Since I popped up the editor to change properties on a particular control, I want to forcibly close it (and cancel changes) if that control loses focus, lest I create confusion for the user. So I attached a handler to the LostFocus event of the edited control, which will force the editor to close. But the handler is not called, even if I click on another control. As I said on the other thread, I suspect this is because the ControlDesigner has somehow intercepted focus, but I don't know how to circumvent that. How can I recognize when the edited control has lost focus in design mode, so I can close my editor? Thanks, Doug | | Douglas Hauck Monday, August 17, 2009 8:47 PM | Ok, after a little (well, a lot) more digging, I have an answer: you have to link to the designer's ISelectionService and use its SelectionChanging and SelectionChanged events. From there, the designer can provide its own events to the outside world. My implementation is as follows (this code is part of my ControlDesigner child class):
public override void Initialize(IComponent component)
{
base.Initialize(component);
InitializeSelectionService();
}
protected override void Dispose(bool disposing)
{
DisposeSelectionService(disposing);
}
#region Focus Handler Implementation
protected ISelectionService selectionService;
bool bControlSelected = false, bPrimarySelection = false;
/// <summary>
/// A delegate to handle the GotFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void GotFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the LostFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void LostFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the GotPrimaryFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void GotPrimaryFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the LostPrimaryFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void LostPrimaryFocusHandler(object sender, FocusArgs e);
/// <summary>
/// The current Focus state, after the FocusChanged event.
/// </summary>
public class FocusArgs : EventArgs
{
/// <summary>
/// A collection of objects representing the selected components.
/// Cast each object to IComponent and use the Site.Name property to
/// identify them.
/// </summary>
public readonly ICollection Selected;
/// <summary>
/// The Primary selected component, i.e., the only selection, or the
/// most recently selected in a group selection.
/// Cast to IComponent and use the Site.Name property to identify.
/// </summary>
public readonly object NewPrimary;
/// <summary>
/// Creates a new FocusArgs object.
/// </summary>
/// <param name="selected">A collection of all selected components.</param>
/// <param name="newPrimary">The primary (only or last selected) component.</param>
public FocusArgs(ICollection selected, object newPrimary)
{
Selected = selected;
NewPrimary = newPrimary;
}
}
/// <summary>
/// The control tied to this designer was selected.
/// </summary>
public event GotFocusHandler GotFocus;
/// <summary>
/// The control tied to this designer was de-selected, or another control
/// was selected.
/// </summary>
public event LostFocusHandler LostFocus;
/// <summary>
/// The control tied to this designer became the only component selected, or
/// if part of a selection group, it is either the last selected or the first
/// in the z-order. Either way, it is the primary target for designer actions.
/// </summary>
public event GotPrimaryFocusHandler GotPrimaryFocus;
/// <summary>
/// The control tied to this designer is either no longer selected, or is
/// no longer the only component selected and another component was selected
/// more recently or is higher in the z-order. Either way, it is no longer
/// the primary target for designer actions.
/// </summary>
public event LostPrimaryFocusHandler LostPrimaryFocus;
private void InitializeSelectionService()
{
selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
if (selectionService != null)
selectionService.SelectionChanged += new EventHandler(selectionService_SelectionChanged);
}
void selectionService_SelectionChanged(object sender, EventArgs e)
{
if (selectionService.GetComponentSelected(Control))
{
if (!bControlSelected && GotFocus != null)
GotFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bControlSelected = true;
if (selectionService.PrimarySelection == Control)
{
if (!bPrimarySelection && GotPrimaryFocus != null)
GotPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = true;
}
else
{
if (bPrimarySelection && LostPrimaryFocus != null)
LostPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = false;
}
}
else
{
if (bPrimarySelection && LostPrimaryFocus != null)
LostPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = false;
if (bControlSelected && LostFocus != null)
LostFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bControlSelected = false;
}
}
private void DisposeSelectionService(bool disposing)
{
if (disposing && selectionService != null)
{
selectionService.SelectionChanged -= new EventHandler(selectionService_SelectionChanged);
}
}
#endregion
- Marked As Answer byAland LiMSFT, ModeratorWednesday, August 19, 2009 12:33 PM
-
| | Douglas Hauck Wednesday, August 19, 2009 12:30 PM | Ok, after a little (well, a lot) more digging, I have an answer: you have to link to the designer's ISelectionService and use its SelectionChanging and SelectionChanged events. From there, the designer can provide its own events to the outside world. My implementation is as follows (this code is part of my ControlDesigner child class):
public override void Initialize(IComponent component)
{
base.Initialize(component);
InitializeSelectionService();
}
protected override void Dispose(bool disposing)
{
DisposeSelectionService(disposing);
}
#region Focus Handler Implementation
protected ISelectionService selectionService;
bool bControlSelected = false, bPrimarySelection = false;
/// <summary>
/// A delegate to handle the GotFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void GotFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the LostFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void LostFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the GotPrimaryFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void GotPrimaryFocusHandler(object sender, FocusArgs e);
/// <summary>
/// A delegate to handle the LostPrimaryFocus event for this Designer's control.
/// </summary>
/// <param name="sender">In this case, the CONTROL attached to the designer,
/// not the designer itself.</param>
/// <param name="e">A FocusArgs object that contains the current focus state.</param>
public delegate void LostPrimaryFocusHandler(object sender, FocusArgs e);
/// <summary>
/// The current Focus state, after the FocusChanged event.
/// </summary>
public class FocusArgs : EventArgs
{
/// <summary>
/// A collection of objects representing the selected components.
/// Cast each object to IComponent and use the Site.Name property to
/// identify them.
/// </summary>
public readonly ICollection Selected;
/// <summary>
/// The Primary selected component, i.e., the only selection, or the
/// most recently selected in a group selection.
/// Cast to IComponent and use the Site.Name property to identify.
/// </summary>
public readonly object NewPrimary;
/// <summary>
/// Creates a new FocusArgs object.
/// </summary>
/// <param name="selected">A collection of all selected components.</param>
/// <param name="newPrimary">The primary (only or last selected) component.</param>
public FocusArgs(ICollection selected, object newPrimary)
{
Selected = selected;
NewPrimary = newPrimary;
}
}
/// <summary>
/// The control tied to this designer was selected.
/// </summary>
public event GotFocusHandler GotFocus;
/// <summary>
/// The control tied to this designer was de-selected, or another control
/// was selected.
/// </summary>
public event LostFocusHandler LostFocus;
/// <summary>
/// The control tied to this designer became the only component selected, or
/// if part of a selection group, it is either the last selected or the first
/// in the z-order. Either way, it is the primary target for designer actions.
/// </summary>
public event GotPrimaryFocusHandler GotPrimaryFocus;
/// <summary>
/// The control tied to this designer is either no longer selected, or is
/// no longer the only component selected and another component was selected
/// more recently or is higher in the z-order. Either way, it is no longer
/// the primary target for designer actions.
/// </summary>
public event LostPrimaryFocusHandler LostPrimaryFocus;
private void InitializeSelectionService()
{
selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
if (selectionService != null)
selectionService.SelectionChanged += new EventHandler(selectionService_SelectionChanged);
}
void selectionService_SelectionChanged(object sender, EventArgs e)
{
if (selectionService.GetComponentSelected(Control))
{
if (!bControlSelected && GotFocus != null)
GotFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bControlSelected = true;
if (selectionService.PrimarySelection == Control)
{
if (!bPrimarySelection && GotPrimaryFocus != null)
GotPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = true;
}
else
{
if (bPrimarySelection && LostPrimaryFocus != null)
LostPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = false;
}
}
else
{
if (bPrimarySelection && LostPrimaryFocus != null)
LostPrimaryFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bPrimarySelection = false;
if (bControlSelected && LostFocus != null)
LostFocus(Control, new FocusArgs(
selectionService.GetSelectedComponents(),
selectionService.PrimarySelection));
bControlSelected = false;
}
}
private void DisposeSelectionService(bool disposing)
{
if (disposing && selectionService != null)
{
selectionService.SelectionChanged -= new EventHandler(selectionService_SelectionChanged);
}
}
#endregion
- Marked As Answer byAland LiMSFT, ModeratorWednesday, August 19, 2009 12:33 PM
-
| | Douglas Hauck Wednesday, August 19, 2009 12:30 PM |
|