Main control to close child - c#

I have one MainControl that contains a ChildControl. The ChildControl has a hide button that would hide itself.
When hidden I expect the MainControl to hook the event and dispose it.
MainControl
ChildControl > Hide button
Can't figure out how I should hook those.
Any tip? Thank you!

You can create an event that will notify the main control that the child control is hidden, and in your main control, handling the event, you can dispose of your control.
Below is a small sample code of how you can go about creating your event for the hidden action.
class MainControl
{
ChildControl childControl;
public MainControl()
{
childControl = new ChildControl();
childControl.VisibilityChanged += childControl_VisibilityChanged;
}
void childControl_VisibilityChanged(object sender, HiddenEvent e)
{
if (e.isHidden)
{
//close control here
}
}
}
public class HiddenEvent : EventArgs
{
public HiddenEvent(bool propertyValue)
{
this.isHidden = propertyValue;
}
public bool isHidden { get; set; }
}
public class ChildControl
{
public event EventHandler<HiddenEvent> VisibilityChanged;
public ChildControl()
{
}
private bool _isHidden;
public bool Control
{
get
{
return _isHidden;
}
set
{
_isHidden = value;
Hidden_Handler(value);
}
}
private void Hidden_Handler(bool isHidden)
{
var handler = VisibilityChanged;
if (handler != null)
VisibilityChanged(this, new HiddenEvent(isHidden));
}
}

As an option you could bind ChildControl's button to a remove command on the main control (using RelativeSource) and let MainControl do all the work

Related

C# Modified control custom Event

Let's say I have a modified control of a textbox
public class resButton : TextBox
{
[Browsable(true)]
[Description("state of TextBox"), Category("Data")]
public string textBoxState
{
get { return this.AccessibleDescription; }
set {
this.AccessibleDescription = value;
}
}
}
And I have added a custom propertie which is based on the AccessibleDescription of that control.
How could I add a custom event to that control ?
I'd like to do a custom Event which fires when "textBoxState" is changed.
public class resButton : TextBox
{
[Browsable(true)]
[Description("state of TextBox"), Category("Data")]
public string textBoxState
{
get { return this.AccessibleDescription; }
set
{
this.AccessibleDescription = value;
if (yourEvent != null)
yourEvent(this, new EventArgs());
}
}
public event EventHandler yourEvent;
}
public class resButtonUsage
{
resButton resbuttonInstance;
public resButtonUsage()
{
resbuttonInstance = new resButton();
resbuttonInstance.yourEvent += resbuttonInstance_yourEvent;
}
void resbuttonInstance_yourEvent(object sender, EventArgs e)
{
// Your implementation
}
}
you must declare event like this sample with existing delegate(EventHandler) or your custom delegate.
after declaring and calling it in setter of your property you can use outside of this class by instancing and declaring this event.

Call parent from custom control

I have a form, on this form is a flowlayoutpanel with multiple custom made TextBoxes
The form overrides the base methode Refresh(), to do some other things also.
Now I'm digging into the parent to eventueally come on the form and do the refresh
this.Parent.Parent.Parent.Refresh();
I want to re-use the control on other forms, so is there another way to do this?
And I know a While(true) is possible:
Boolean diggToParent = true;
var parent = this.Parent;
while (diggToParent)
{
if (parent.Parent != null)
{
parent = parent.Parent;
}
else
break;
}
parent.Refresh();
But is there a cleaner way to do this?
You can solve this by creating and raising an event that is handled by the parent form:
public class MyUserControl : UserControl
{
// ...
public event EventHandler RequestRefresh;
// Call this method whenever you want the parent to refresh
private void OnRequestRefresh()
{
if (RequestRefresh != null)
RequestRefresh(this, EventArgs.Empty);
}
}
In the parent form (or the container that should be refreshed), you add an event handler, e.g.
public class MyParentForm : Form
{
public MyParentForm()
{
InitializeComponent();
userCtrl.RequestRefresh += userCtrl_RequestRefresh;
}
// Do whatever the parent thinks is necessary to refresh.
public void userCtrl_RequestRefresh(object sender, EventArgs e)
{
Refresh();
}
// ...
}
This way the parent form can decide what to do when the user control requests a refresh. For details on events, see this link.

Creating Smart Tag for Form (not other control) using c#

As the Form of System.Windows.Forms inherits from Control, I was wondering if there is a way to create a Custom Form and its Designer with some options (shortcuts) to create a title or somthings like that.
I tried this, but nothings happend, the Form I calles ManagedForm
[Designer(typeof(ManagedFormDesigner))]
public class ManagedForm : Form{
//code here
}
[PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class ManagedFormDesigner : ControlDesigner {
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists {
get {
if (actionLists == null) {
actionLists = new DesignerActionListCollection();
actionLists.Add(new ManagedFormDesignerActionList(this.Component));
}
return actionLists;
}
}
}
public class ManagedFormDesignerActionList : DesignerActionList {
private ManagedForm managedForm = null;
private DesignerActionUIService designerActionUISvc = null;
public ManagedFormDesignerActionList(IComponent component) : base(component) {
this.managedForm = component as ManagedForm;
this.designerActionUISvc =
GetService(typeof(DesignerActionUIService))
as DesignerActionUIService;
}
public override DesignerActionItemCollection GetSortedActionItems() {
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "CreateTitle", "Create Title", "Appearence", true));
return items;
}
public void CreateTitle() {
Panel pTitulo = new Panel();
pTitulo.Size= new Size(100,25);
pTitulo.Dock = DockStyle.Top;
(this.Component as ManagedForm).Controls.Add(pTitulo);
}
}
Action list are show when you click on the little arrow on the control inside a form (or on a component on the bottom of the designer if the object is a component).
Other things you can do is to manage verbs.
Verbs Handling is implemented on the ControlDesigner class (ManagedFormDesigner in your case).
You can see verbs clicking right mouse button or on the bottom of the properties (i.e. TabControl ha 2 verbs, add tab and remove tab).
You can implement verbs adding to ControlDesigner (or ComponentDesigner) class something like this
private DesignerVerbCollection _verbs;
public override DesignerVerbCollection Verbs
{
get
{
if (_verbs == null)
{
_verbs = new DesignerVerbCollection();
_verbs.Add(new DesignerVerb("Create Title", new EventHandler(MyCreateTitleHandler)));
}
return _verbs;
}
}
private void MyCreateTitleHandler(object sender, EventArgs e)
{
// Do here something but take care to show things via IUIService service
IUIService uiService = GetService(typeof(IUIService)) as IUIService;
}

Need know which element get focus when another element lost focus

I have many controls in a window. Requirement is to know which control gets the focus from the lost focus event of a control.
Say, A Text box and it has the focus. Now I am clicking a button. while doing this, need to know that i am moving the focus to button from the Text box lost focus event.
So how could i achieve this..
This is what I did and its working for me
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
lostFocusControl = e.OldFocus;
}
private void PauseBttn_PreviewKeyDown(object sender, KeyEventArgs e)
{
/**invoke OnPreviewLostKeyboardFocus handller**/
}
Hope it will help
You can use FocusManager to handle this,
In your LostFocusEvent, Use FocusManager.GetFocusedElement()
uiElement.LostFocus+=(o,e)=>
{
var foo=FocusManager.GetFocusedElement();
}
The following class watches the FocusManager for changes in focus, it's a looped thread so you have to put up with the fact that it's running but when focus changes it will just raise an event letting you know what changed.
Just add these two classes to your project.
public class FocusNotifierEventArgs : EventArgs
{
public object OldObject { get; set; }
public object NewObject { get; set; }
}
public class FocusNotifier : IDisposable
{
public event EventHandler<FocusNotifierEventArgs> OnFocusChanged;
bool isDisposed;
Thread focusWatcher;
Dispatcher dispatcher;
DependencyObject inputScope;
int tickInterval;
public FocusNotifier(DependencyObject inputScope, int tickInterval = 10)
{
this.dispatcher = inputScope.Dispatcher;
this.inputScope = inputScope;
this.tickInterval = tickInterval;
focusWatcher = new Thread(new ThreadStart(FocusWatcherLoop))
{
Priority = ThreadPriority.BelowNormal,
Name = "FocusWatcher"
};
focusWatcher.Start();
}
IInputElement getCurrentFocus()
{
IInputElement results = null;
Monitor.Enter(focusWatcher);
dispatcher.BeginInvoke(new Action(() =>
{
Monitor.Enter(focusWatcher);
results = FocusManager.GetFocusedElement(inputScope);
Monitor.Pulse(focusWatcher);
Monitor.Exit(focusWatcher);
}));
Monitor.Wait(focusWatcher);
Monitor.Exit(focusWatcher);
return results;
}
void FocusWatcherLoop()
{
object oldObject = null;
while (!isDisposed)
{
var currentFocus = getCurrentFocus();
if (currentFocus != null)
{
if (OnFocusChanged != null)
dispatcher.BeginInvoke(OnFocusChanged, new object[]{ this, new FocusNotifierEventArgs()
{
OldObject = oldObject,
NewObject = currentFocus
}});
oldObject = currentFocus;
}
}
Thread.Sleep(tickInterval);
}
}
public void Dispose()
{
if (!isDisposed)
{
isDisposed = true;
}
}
}
Then in your code behind, create a new instance of the Focus Notifier class and hook on to it's OnFocusChanged event, remember to dispose it at the end or the thread will keep your app open.
public partial class MainWindow : Window
{
FocusNotifier focusNotifier;
public MainWindow()
{
InitializeComponent();
focusNotifier = new FocusNotifier(this);
focusNotifier.OnFocusChanged += focusNotifier_OnFocusChanged;
}
void focusNotifier_OnFocusChanged(object sender, FocusNotifierEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.OldObject);
System.Diagnostics.Debug.WriteLine(e.NewObject);
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
focusNotifier.Dispose();
base.OnClosing(e);
}
}
have you tried to register your controls to Control.LostFocus event and there you can check for Form.ActiveControl, to determine which control currently has the focus

Getting update from UserControl

Can someone tell me how can I have a feature in my UserControl, that can let the host windowsform know what is the control is doing?
For example my usercontrol has a filebrowser, and if user uses this file browser to open a file I want in the statusstrip bar of my form to write "Loading file(s)".
Will this require using events? if so, how can I have a single event inside usercontrol to report anything it does (then I guess I have to call this event in all methods in the usercontrol).
Simple
Yes, expose an event on the user control that the Form can subscribe to. You should use the standard event pattern:
class MyUserControl : UserControl
{
public event EventHandler<EventArgs> FileOpened;
protected virtual void OnFileOpened(EventArgs e)
{
EventHandler<EventArgs> handler = FileOpened;
if (handler != null)
handler(this, e);
}
}
Then when the file is opened you call OnFileOpened(EventArgs.Empty) which fires the event.
With custom EventArgs
Now the Form probably needs to know what file was opened. You could expose a property on the user control that the Form can use to find out, or you can provide that information in your event like so:
public class FileOpenedEventArgs : EventArgs
{
private string filename;
public FileOpenedEventArgs(string filename)
{
this.filename = filename;
}
public string Filename { get { return filename; } }
}
class MyUserControl : UserControl
{
public event EventHandler<FileOpenedEventArgs> FileOpened;
protected virtual void OnFileOpened(FileOpenedEventArgs e)
{
EventHandler<FileOpenedEventArgs> handler = FileOpened;
if (handler != null)
handler(this, e);
}
}
Then you fire the event with OnFileOpened(new FileOpenedEventArgs(filename)).
Optimal
When you create an event handler public event delegate Name;, you are allocating storage for the delegate on your object. Objects (especially Controls) often have a huge number of events that are never subscribed to. That's a whole lot of allocated storage not being used. There's an optimization built into the framework in the form of a EventHandlerList. This handy object stores event handlers only when they are actually used. All System.Windows.Forms.Control objects derive from System.ComponentModel.Component and it already provides an (protected) EventHandlerList that you can access in your derived Control.
To use it, you first create a static object that uniquely identifies your event, and then you provide the add {} and remove {} methods manually. Like so:
class MyUserControl : UserControl
{
private static readonly object FileOpenedKey = new Object();
public event EventHandler<FileOpenedEventArgs> FileOpened
{
add { Events.AddHandler(FileOpenedKey, value); }
remove { Events.RemoveHandler(FileOpenedKey, value); }
}
protected virtual void OnFileOpened(FileOpenedEventArgs e)
{
var handler = (EventHandler<FileOpenedEventArgs>)Events[FileOpenedKey];
if (handler != null)
handler(this, e);
}
}
Yes, you will need to create an event and subscribe to it. One suggestion following the standard pattern for events:
enum ControlStatus {Idle, LoadingFile, ...}
class StatusChangedEventArgs : EventArgs
{
public ControlStatus Status {get; private set;}
public StatusChangedEventArgs(ControlStatus status)
: base()
{
this.Status = status;
}
}
partial class MyControl : UserControl
{
public ControlStatus Status {get; private set;}
public event EventHandler<StatusChangedEventArgs> StatusChanged;
protected virtual void OnStatusChanged(StatusChangedEventArgs e)
{
var hand = StatusChanged;
if(hand != null) hand(this, e);
}
void LoadFiles()
{
...
Status = ControlStatus.LoadingFiles;
OnStatusChanged(new StatusChangedEventArgs(this.Status));
...
Status = ControlStatus.Idle;
OnStatusChanged(new StatusChangedEventArgs(this.Status));
}
}
partial class MyHostWindowsForm : Form
{
public MyHostWindowsForm()
{
var ctl = new MyControl();
...
ctl.StatusChanged += ctl_StatusChanged;
}
void ctl_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch(e.Status)
{
case ControlStatus.Idle:
statusStripBar.Text = null;
break;
case ControlStatus.LoadingFiles:
statusStripBar.Text = "Loading file(s)";
break;
...
}
}
}

Categories

Resources