I have this project where i contain all my panel instances in my main form.
PanelA aPanelA = new PanelA;
PanelB aPanelB = new PanelB;
This is the form where the program.cs load when it starts.
Because i would like to have a centralize place for each panel calling one another method within them hence i declare them in main. In main, i also make some methods doing certain function in these panel since they are declare in main.
void setPanelA (int iNumber){...}
void setPanelB (string strString){...}
The problem is how would a widget in PanelA call the method setPanelB() via main?
Main.setPanelB("Hello World);
I know i can declare PanelA and PanelB as static. But is this the only way to do it? Because if i declare static to both Panel, i will need to declare some instances within Panel as static too..
I also do not wish to declare PanelA in PanelB or via versa because i could have many type of panels and this would make my code very untidy.
*Edited I had add a sample code here
namespace TestPanel
{
public partial class Form1 : Form
{
PanelA aPanelA = new PanelA();
PanelB aPanelB = new PanelB();
//IT IS POSSIBLE TO HAVE TENS OF DIFFERENT TYPE OF PANEL
public Form1()
{
InitializeComponent();
}
//CENTRAL LOCATION WHERE ALL PANEL COULD CALL EACH OTHER METHOD
public void setPanelACentral(int iNew)
{
aPanelA.setPanelA(iNew);
}
public void setPanelBCentral(string strNew)
{
aPanelB.setPanelB(strNew);
}
}
public class PanelA
{
int i = 0;
public void setPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB
{
string str = "";
public void setPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void changePanelA()
{
int i = 1000;
Form1.setPanelACentral(i); //<- This the part where i am asking
}
}
}
The following code demonstrates adding Events to both your Panel types and Form1. By doing this, you can raise an event in your Panel that Form1 will have registered to handle.
public partial class Form1 : Form
{
protected EventHandler<PanelEventArg> OnSetPanelA = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected EventHandler<PanelEventArg> OnSetPanelB = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected List<PanelBase> panels;
public Form1() : base()
{
panels = new List<PanelBase>
{
new PanelA(),
new PanelB()
};
foreach (var panel in panels)
{
OnSetPanelA += panel.OnSetPanel;
OnSetPanelB += panel.OnSetPanel;
panel.OnSomeEvent += Form1_OnSomeEvent;
}
foreach (var panel in panels.OfType<PanelB>())
{
panel.OnChangePanelA += Form1_OnChangePanelA;
}
InitializeComponent();
}
protected void SetPanelA(int iNew)
{
foreach (var panel in panels.OfType<PanelA>())
{
panel.SetPanelA(iNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void SetPanelB(string strNew)
{
foreach (var panel in panels.OfType<PanelB>())
{
panel.SetPanelB(strNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void Form1_OnSomeEvent(object sender, EventArgs e)
{
// handles events raised by the panel.
}
protected void Form1_OnChangePanelA(object sender, int iNew)
{
SetPanelA(iNew);
}
}
Helper Types I'm including: PanelEventArg, PanelBase
public class PanelEventArg : EventArgs
{
public PanelBase Panel { get; set; }
}
public class PanelBase //: Panel
{
public EventHandler OnSomeEvent = new EventHandler((sender, e) => { }); //stub;
public void OnSetPanel(object sender, PanelEventArg e)
{
if (!Equals(e.Panel, this))
{
//the panel being set is not this panel instance
}
}
}
Declaring PanelA and PanelB, with inheritance and new Event for PanelB
public class PanelA : PanelBase
{
int i = 0;
public void SetPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB : PanelBase
{
public EventHandler<int> OnChangePanelA = new EventHandler<int>((sender, e) => { }); //stub
string str = "";
public void SetPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void ChangePanelA()
{
OnChangePanelA(this, 1000);
}
}
Related
I am trying to access the dcam in the internal class. The initialization process starts when it starts.
internal class Ham4MPBase : CameraBase, IDisposable
{
private bool sf;
private Dcam dcam;
public bool Initialize()
{
sf = DcamApi.init();
if (sf)
{
Dcam aDcam = new Dcam();
if (!aDcam.dev_open(0))
{
aDcam = null;
MessageBox.Show("Camera init/open failed");
}
dcam = aDcam;
MessageBox.Show("Camera init/open success");
_initialized = true;
return _initialized;
}
else
{
MessageBox.Show("Camera init failed");
}
}
}
Here, I have data inside of dcam.
Now imagine that I have a button in another namespace where after pressing it would start to acquire image, like below:
public partial class CameraControlPanel : UserControl
{
private Dcam dcam;
private void buttonImageAquire_Click(object sender, EventArgs e)
{
if (dcam == null)
{
MessageBox.Show("Internal Error: dcam is null");
return; // internal error
}
string text = "";
//Start acquisition
m_cap_stopping = false;
dcam.m_capmode = DCAMCAP_START.SEQUENCE; //Continuous Acquisiton
// ....
I am stuck here because dcam shows to be null. How can I expose data from this internal class into my form?
Expose a property to the user control to set the dcam
public partial class CameraControlPanel : UserControl
{
private Dcam mydcam;
public Dcam Camera { get => mydcam; set => mydcam = value; }
}
and then in the form where the control is initialized
public partial class Form1 : Form
{
public Form1()
{
InitializeComponents();
}
protected override OnLoad(EventArgs e)
{
cameraControlPanel1.Camera = ...
}
}
//MdiParent mainparent.cs
public static void lodforweb()
{
frm_webcs frmload_webcs = new frm_web
{
MdiParent = this
};
frmload_webcs.Show();
}
//Context menu class
//Cl_contextmenu.cs
public bool OnContextMenuCommand()
{
if (commandId == (2020)
{
mainparent.lodforweb();
return true;
}
}
}
// having a problem with "this" using static method
// instantiating does not work also.
From the comments:
once I right click the child form context menu popups. I want to
generate another child form and should be child of mainparent
Also provided from the comments:
private void childform_Load(object sender, EventArgs e) {
cl_chromebrowser urload = new cl_chromebrowser();
panel1.Controls.Add(urload.choniumeload("www.site.com"));
urload.chromebrowser.MenuHandler= new cl_contexmenu();
}
So your child form is called "childform". Add a static member that holds a reference to the MDI parent, and set it in the Load() event:
public static Form MyMdiParent;
private void childform_Load(object sender, EventArgs e)
{
// ... your existing code from above ...
childform.MyMdiParent = this.MdiParent;
}
Now you can use that MDI parent directly from your context menu:
public bool OnContextMenuCommand()
{
if (commandId == 2020)
{
if (childform.MyMdiParent != null)
{
childform.MyMdiParent.Invoke((MethodInvoker)delegate ()
{
frm_webcs frmload_webcs = new frm_webcs();
frmload_webcs.MdiParent = childform.MyMdiParent;
frmload_webcs.Show();
});
}
}
return true;
}
I have a ListView that changes. This ListView is inside LinearLayout that also has an Icon that shows as a checkmark if the ListView items include an item of a certain type. It shows an "X" if none of the items are of that type.
In the code below, the Console.WriteLine works.
How do I update the Icon (aka call the Redraw function) after a NotifyDataSetChanged has been called on the ListView adapter. The function is outside of the scope of the observer and cannot be called inside the OnChanged.
private void Init () {
view = ((Activity)cx).LayoutInflater.Inflate(Resource.Layout.MyPage, this);
eventsListAdapter?.Dispose();
eventsListAdapter = new EventsAdapter(
context,
EventListDisplay.DefaultView,
dateCurrentlyDisplayed);
var myObserver = new MyDataSetObserver();
eventsListAdapter.RegisterDataSetObserver(myObserver);
}
private void Redraw () {
// UPDATE ICON HERE
}
public class MyDataSetObserver : DataSetObserver
{
public override void OnChanged()
{
base.OnChanged();
Console.WriteLine("Change was observerd");
OnDataChanged(new DataChangedEventArgs() { DataChanged = 1, TimeChanged = DateTime.Now });
// This area is hit, but how do I call the Redraw method above? It is out of scope
}
}
/// EDIT: Something I've Tried THAT WORKS! Anything seem off about it?
private void Init () {
view = ((Activity)cx).LayoutInflater.Inflate(Resource.Layout.MyPage, this);
eventsListAdapter?.Dispose();
eventsListAdapter = new EventsAdapter(
context,
EventListDisplay.DefaultView,
dateCurrentlyDisplayed);
var myObserver = new MyDataSetObserver();
eventsListAdapter.RegisterDataSetObserver(myObserver);
myObserver.DataChanged += OnDataChanged;
}
private void Redraw () {
// UPDATE ICON HERE
}
private void OnDataChanged(object sender, EventArgs e) {
Redraw();
}
// Added the last four event handler pieces
public class MyDataSetObserver : DataSetObserver
{
public override void OnChanged()
{
base.OnChanged();
g.ToastShort("Change was observerd");
}
public event EventHandler DataChanged;
protected virtual void OnDataChanged(EventArgs e)
{
EventHandler handler = DataChanged;
handler?.Invoke(this, e);
}
public delegate void DataChangedEventHandler(object sender, DataChangedEventArgs e);
public class DataChangedEventArgs : EventArgs
{
public int DataChanged { get; set; }
public DateTime TimeChanged { get; set; }
}
}
You can use messaging-center to notify your activity to call Redraw() when OnChanged hit.
The MessagingCenter is a simple way to reduce coupling, especially
between view models. It can be used to send and receive simple
messages or pass an argument between classes. Classes should
unsubscribe from messages they no longer wish to receive.
In the OnChanged(), send a message every time it is hit:
public override void OnChanged()
{
base.OnChanged();
Console.WriteLine("Change was observerd");
// This area is hit, but how do I call the Redraw method above? It is out of scope
MessagingCenter.Send<object>(this, "needRedraw");
}
In your Init(), Subscribe the needRedraw message and call redraw whenever the "needRedraw" message is sent:
private void Init()
{
view = ((Activity)cx).LayoutInflater.Inflate(Resource.Layout.MyPage, this);
eventsListAdapter?.Dispose();
eventsListAdapter = new EventsAdapter(
context,
EventListDisplay.DefaultView,
dateCurrentlyDisplayed);
var myObserver = new MyDataSetObserver();
eventsListAdapter.RegisterDataSetObserver(myObserver);
MessagingCenter.Subscribe<object>(this, "needRedraw", (sender) => {
// do something whenever the "needRedraw" message is sent
Redraw();
});
}
Thank you #Tyddlywink for your comment: "youll need to create [an Event] in your MyDataSetObserver class and fire it"
I used this as a resource for adding Events: https://learn.microsoft.com/en-us/dotnet/standard/events/
Here are the updates I added to trigger my Redraw() function:
private void Init () {
view = ((Activity)cx).LayoutInflater.Inflate(Resource.Layout.MyPage, this);
eventsListAdapter?.Dispose();
eventsListAdapter = new EventsAdapter(
context,
EventListDisplay.DefaultView,
dateCurrentlyDisplayed);
var myObserver = new MyDataSetObserver();
eventsListAdapter.RegisterDataSetObserver(myObserver);
myObserver.DataChanged += OnDataChanged;
}
private void Redraw () {
// UPDATE ICON HERE
}
private void OnDataChanged(object sender, EventArgs e) {
Redraw();
}
public class MyDataSetObserver : DataSetObserver
{
public override void OnChanged()
{
base.OnChanged();
// To be honest, I don't know what int DataChanged wants.. so arbitrarily set it to 1.
OnDataChanged(new DataChangedEventArgs() { DataChanged = 1, TimeChanged = DateTime.Now });
}
public event EventHandler DataChanged;
protected virtual void OnDataChanged(EventArgs e)
{
EventHandler handler = DataChanged;
handler?.Invoke(this, e);
}
public delegate void DataChangedEventHandler(object sender, DataChangedEventArgs e);
public class DataChangedEventArgs : EventArgs
{
public int DataChanged { get; set; }
public DateTime TimeChanged { get; set; }
}
}
Currently in my program a user opens form 1 to create a new instance of a class and it is then saved to a list. After form 1 closes I would like the main form to reload and show the updated list on the screen. I am having trouble figuring out how to refresh the main navigation and how I would get the list to show on the form.
MainNaviagation
public partial class MainNavigation : Form
{
private Model m_modelObj;
public MainNavigation(Model modelObj)
{
InitializeComponent();
m_modelObj = modelObj;
m_modelObj.ChocolateAdded += m_modelObj_ChocolateAdded;
}
void m_modelObj_ChocolateAdded(Chocolate newChocolate)
{
//whole list of chocolates
List<Chocolate> chocolateList = m_modelObj.ChocolateList;
}
private void button1_Click(object sender, EventArgs e)
{
string candy = comboBox1.SelectedItem.ToString();
Form1 aForm1 = new Form1(textBox1.Text, candy, m_modelObj);
aForm1.ShowDialog();
}
}
Model Class:
{
public delegate void ChocolateAddedEventHander(Chocolate newChocolate);
public class Model
{
public event ChocolateAddedEventHander ChocolateAdded;
public List<Chocolate> ChocolateList = new List<Chocolate>();
public void AddChocolateInList(Chocolate chocolate)
{
ChocolateList.Add(chocolate);
if (ChocolateAdded != null)
ChocolateAdded(chocolate);
}
}
form1
public partial class Form1 : Form
{
Model m_model;
public Form1(string name, string candy, Model modelObj)
{
InitializeComponent();
m_model = modelObj;
string str = name + " selected : ";
label1.Text = str;
}
private void button1_Click(object sender, EventArgs e)
{
Chocolate newChocolate = new Chocolate(comboBoxChocolateSelection.SelectedItem.ToString(), 12.5, true, 2);
m_model.AddChocolateInList(newChocolate);
this.Close();
}
}
chocolates
public class Chocolate
{
#region Fields
public string flavor;
public double cost;
public bool giftWrap;
public int quantity;
#endregion End of Fields
#region Constructors
public Chocolate(string flavor, double cost, bool giftWrap, int quantity)
{
this.flavor = flavor;
this.cost = cost;
this.giftWrap = giftWrap;
this.quantity = quantity;
}
#endregion End of Constructors
}
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