I'm using c# on VS2012
After installing NI Measurement Studio 2013 for Visual Studio 2012, I created a windows form and added a toggle switch to it.
in the code I wanted to check if the toggle switch state has changed, but I am running into problem, I am sure that like may of the questions asked here, this is a simple matter for other, but I am stuck.
I keep getting the error:
Error 1 The event 'NationalInstruments.UI.WindowsForms.Boolean.StateChanged' can only appear on the left hand side of += or -=
Reading other posts I saw discussions on how the .NET framework does not allow events to be directly modified outside the class that define it, but in this case I am not trying to modify it, just get its state??
What am I doing wrong please?
Thanks,
Here is my code:
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void switch1_StateChanged(object sender, ActionEventArgs e)
{
if (switch1.StateChanged = true)
{
//do something
}
}
}
}
You can use this:
if(switch1.StateChanged)
{
//do something
}
In C# you use == to compare primitive values.
The error comes from the fact that you need == in C# for comparison, eg:
if (switch1.StateChanged == true)
{
//do something
}
However, that still doesn't make sense as StateChanged is an event. I would have expected to see something like:
public Form1()
{
InitializeComponent();
StateChanged += switch1_StateChanged;
}
private void switch1_StateChanged(object sender, ActionEventArgs e)
{
//do something
}
This registers your StateChanged event handler, and the code inside it will be executed when the state change event is fired.
I think you may be misunderstanding the fact that an event is one or more functions (delegates) which get executed when the event happens, as opposed to it being some sort of boolean flag (which it isn't). Hope this helps!
Your code
switch1.StateChanged = true
is an assignment (like x = 5). Probably you want a comparison (x == 5 or b == true) where you get a true or false (that's why you can remove the == true part.
But since StateChanged seems to be an event, you assign methods to this event which will be called after StateChanged. Your private method switch1_StateChanged is probably already such a method. Thus you don't need to check for StateChanged since this method is only called when the State was changed.
I ended up using this code:
private void switch1_StateChanged(object sender, ActionEventArgs e)
{
if (switch1.Value)
{
}
else
{
led1.Value = false;
}
}
Related
I've been reading this MSDN article and this question to try to understand events in .NET. Unfortunately, its not clicking for me and I'm having a lot of trouble. I'm trying to integrate this technique into my project, with little success.
Basically, I've got this class that will read numbers. Whenever it encounters a new number, I want it to fire an event called numberChanged.
So, I set up my event public event EventHandler numberChanged;. Later on, I fire my event when it encounters a number than isn't the same as the previous one.
if(currentNumber != previousNumber){
if(numberChanged != null){
numberChanged(this, new EventArgs());
}
}
But then I'm having trouble 'subscibing' to this event. If I do numberChanged += [something to do here] it errors saying that numberChanged is an event and not a type.
Is my explanation clear enough for some advice to be offered? Many thanks.
There are a number of ways to handle it, the most basic is to create a function:
public void MyNumberChangedHandler(object sender, EventArgs e)
{
//Your code goes here that gets called when the number changes
}
You then subscribe (one time only, usually in the constructor) by going:
numberChanged += MyNumberChangedHandler;
Or, you can use something called an anonymous (lambda) method, which is also assigned in your constructor (typically):
numberChanged += (sender, e) => {
//Your code here to handle the number changed event
};
To expand a little bit, care must be taken when using the lambda approach since you can create memory leaks and zombie objects. The .NET memory garbage collector is a mark-and-sweep system that removes objects when they are no longer in use. This post shows how hard it is to remove lambda event handlers: How to remove a lambda event handler .
Having an active event handler can keep your object alive even if it has been disposed! Here is an example of creating a zombie object (doesn't run in Fiddle but you can copy to your own console app) https://dotnetfiddle.net/EfNpZ5
Prints out:
I'm still alive
I'm still alive
I was disposed!
Press any key to quit
I'm still alive
I'm still alive
I'm still alive.
As everything else in the C# programming world, the events concept also follows specific rules and has it's own syntax. The wording is as follows:
an event defined as EventHandler is actually just a shortcut for a special method (delegate) signature - public delegate void EventHandler(object sender, EventArgs e)[1]. Whenever you have a signature in C# you always know what you need to write on the right sight or as a parameter, in order to connect/call some objects/methods/and so on.
after the event is defined, you need to subscribe in order to be informed whenever something happens. The syntax for subscribing an event is +=. Naturally for unsubscribing is -=. MSDN says that the syntax should be object.event += eventHandler (or object.event += new EventHandler(eventHandler);)
so after an event is defined (event Event SomeEvent;) all that left is to create a method that can be bound to this event. This method has to have the same signature as the EventHandler, so it should match the signature of [1] and can be something like private void numberChangedEventHandler(object sender, EventArgs eventArguments)
Now you know what you need to write on the right side of +=.
An example:
public class NumberSequence
{
// numbers to be compared
private readonly List<int> numbers = new List<int>();
// used to generate a random collection
private readonly Random random = new Random();
// tell me if the previous and next number are different
public event EventHandler DifferentNumbersEvent;
public NumberSequence()
{
// fill the list with random numbers
Enumerable.Range(1, 100).ToList().ForEach(number =>
{
numbers.Add(random.Next(1, 100));
});
}
public List<int> Numbers { get { return numbers; } }
public void TraverseList()
{
for (var i = 1; i < this.numbers.Count; i++)
{
if (this.numbers[i - 1] != this.numbers[i])
{
if (this.DifferentNumbersEvent != null)
{
// whoever listens - inform him
this.DifferentNumbersEvent(this, EventArgs.Empty);
}
}
}
}
}
Now before the class is used, define the event handler, that will listen and will be called, when the event is fired (wording again):
private void differentNumberEventHandler(Object sender, EventArgs eventArguments)
{
Console.WriteLine("Different numbers...");
}
And the usage:
var ns = new NumberSequence();
ns.DifferentNumbersEvent += differentNumberEventHandler;
ns.TraverseList();
Everything else is just syntactic sugar for this notation (lambda / anonymous methods / ...), for example:
object.Event += (s, e) => { // code ... }; is the same as object.Event += (Object sender, EventArgs eventArguments) => { // code ... };. Do you recognise the signature? - it is the same as the private void differentNumberEventHandler....
Often we need to pass information through the event, in this case maybe we want to see the two numbers. C# allows you to do this easily using custom event arguments. Just create a class that inherits the EventArgs class and add properties for the data that should be passed, in this case the numbers:
public class NumbersInfoEventArgs : EventArgs
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
And then specify, when declaring the event, that it will pass data of type NumbersInfoEventArgs (signatures again):
public event EventHandler<NumbersInfoEventArgs> DifferentNumbersEvent;
...
this.DifferentNumbersEvent(this, new NumbersInfoEventArgs
{
Number1 = this.numbers[i - 1],
Number2 = this.numbers[i]
});
And last but now least, the signature of the event handler should match the signature of the event:
private void differentNumberEventHandler(Object sender, NumbersInfoEventArgs eventArguments)
{
Console.WriteLine("Different numbers {0} - {1}", eventArguments.Number1, eventArguments.Number2);
}
And voila, the output is:
Different numbers 89 - 86
Different numbers 86 - 53
Different numbers 53 - 12
Different numbers 12 - 69
you can subscribe the event in this way:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var num = new Number();
num.numberChanged +=(s,e) =>{
Console.WriteLine("Value was changed to {0}",num.Value); // in the demo below you can find another implementation for this sample using custom events
};
num.Value=10;
num.Value=100;
}
}
public class Number{
public event EventHandler numberChanged;
private int _value=0;
public int Value
{
get{
return _value;
}
set{
if(value!=_value){
_value=value;
if(numberChanged!=null)
numberChanged(this,null);
}
}
}
}
explanation:
since the EventHandler delegate has 2 parameters (sender, eventArgs) as mentioned here, you need to pass these params and I passed them as s and e
another way to subscribe this event like this:
var num = new Number();
num.numberChanged += NumberChanged_Event; // below is the delegate method
public void NumberChanged_Event(object sender,EventArgs e)
{
// your code goes here
}
I updated the demo to work with you own delegate to pass the old value and new value which can help in many cases.
here a working demo
This may have been asked several times, but I don't know what to search for..
Anyway. I have a class called Character. Inside of it I want to have a collision component that I have called RectangleCollision. Inside of it there is a function called IsOverlapping that checks for overlap.
I want to have a function that can be modified for each game object. For example create a function called OnBeginOverlap(); that will fire everytime the collision component detects a collision.
Is there any way that I can bind this function as delegate or event? Or something?
You have to read about events and delegates. There are plenty of examples on the web. The easiest I managed to find when I was trying to understand the subject was this:
The Simplest C# Events Example Imaginable
You can also check out the below (you can compile this as console application):
class Character
{
public delegate void OverlappingHandler(Character character, EventArgs e);
public event OverlappingHandler OverlappingEvent;
public void IsOverlapping()
{
bool overlapping = true;
if (overlapping)
{
if (OverlappingEvent != null)
{
OverlappingEvent(this, null);
}
}
}
}
class Program
{
static void Main(string[] args)
{
Character c = new Character();
c.OverlappingEvent += OverlappingEventHandler;
c.OverlappingEvent += OverlappingSecondEventHandler;
c.IsOverlapping();
Console.Read();
}
static void OverlappingEventHandler(Character character, EventArgs e)
{
Console.WriteLine("We have overlapping here!!");
}
static void OverlappingSecondEventHandler(Character character, EventArgs e)
{
Console.WriteLine("Seriously, we have overlapping !!");
}
}
So step by step:
Create a delegate, which is a bridge between your event and the code you want to run when event is triggered. You give parameters to a delegate, which are (object sender, EventArgs e) - in this example sender is the Character class, arguments are used to send additional info - for example type of character.
Create event of our delegate type
In our function IsOverlapping() there would be your logic checking if there is overlapping happening. If there is, you fire up event. You should check first if there is anything connected to the event (hence the if (OverlappingEvent != null)) - if some there is something, fire up the event.
In the Main() you create an instance of the class and...
Subscribe your event handlers to it, so the code that should be executed when the event is triggered. I connected two methods, just to show that you can subscribe more than one.
Now when you run c.IsOverlapping() this is what happens:
your logic to check overlapping runs,
if there is overlapping, there will be a check if OverlappingEvent has code subscribed (it does in Main()),
if it does event will be triggered,
code subscribed to the event runs - in this case your code in Main().
You can compile this as console app and it will display 2 lines:
We have overlapping here!!
Seriously, we have overlapping !!
Hope this helps.
I want to convert event code using e.cancel to RX code.
public void CounsumerMethod(object sender, EventArgs e) {
if (x == 0) {
e.Cancel = false;
}
}
You cannot effectively convert this code to proper Rx code, because this is not a Pure event - the caller of the event (i.e. the framework code) will immediately check the "Cancel" value, whereas Rx will not guarantee that it will set that variable in-context. You'll make an Observable that works sometimes and mysteriously fails in other scenarios.
As per MSDN guidelines we need to put all the app's settings into the SettingsPane and then the app should update all pages when the settings is applied.
In my app I need to have a reset option which brings the app to the default settings. There are 2 pages, Calendar.xaml and HistoryStatistics.xaml that i need to update when the reset button is pressed. All the data of the app is put in a singleton class called CycleManager. I have used a SettingsFlyout control from the Callisto Toolkit.
App.Xaml
Registered the settings in the App.xaml
SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
and in OnCommandsRequested function, created the reset handler
var reset = new SettingsCommand("reset", "Reset", (handler) =>
{
var settings = new SettingsFlyout();
settings.Content = new ResetUserControl();
settings.HeaderBrush = new SolidColorBrush(_background);
settings.Background = new SolidColorBrush(_background);
settings.HeaderText = "Reset";
settings.IsOpen = true;
});
args.Request.ApplicationCommands.Add(reset);
CycleManager.cs
In the CycleManager class, there is a m_Reset variable,its setter and getter and an event handler called ResetClicked
public event EventHandler ResetClicked;
public bool Reset
{
get
{
return m_reset;
}
set
{
m_reset = value;
if (ResetClicked != null)
ResetClicked(this, EventArgs.Empty);
}
}
Next is the part where i have associated this handler in my first class calendar.xaml
Calendar.xaml
In the constructor of the class I declare the event handler
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
followed by the definition of the event handler
private async void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
try
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
}
catch (Exception)
{
}
}
CreateCalendar();// UI is loaded
}
In the constructor of the HistoryStatistics.xaml I have done the same thing as above
HistoryStatistics.xaml
public HistoryStatistics()
{
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
}
and defined
private void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
Now the problem
Is this the right approach?
When Reset is pressed in the first from the second page(HistoryStatistcs), the reset clicked function declared in the first page(Calendar.xaml.cs) is called first and then the one in HistoryStatistics. And both gets executed async! :(
Is this a right behaviour?
This question is quite long. Hope everybody understood the scenario and question.
There is nothing wrong with the behaviour you outlined. Two pages subscribe to an event and event uses multi cast delegate which means they will both get fired.
I think you need a simpler behaviour here. Each xaml page should subscribe to that event on OnNavigatedTo and should unsubscribe in OnNavigatedFrom.
That way only one of the two actually executes the cleanup.
The complexity/confusion is likely coming because of not using the MVVM (model, view, and view model) separation. you may want to read about this. keeping the separation helps. Below are few pointers on this. but not necessarily a full design for your app.
in this example: CycleManager.Instance is kind of serving the model (the data). You may want to rename ResetClicked to SettingChanged and think of the event as notification for clients that one or more settings properties exposed has changed. It should also expose ResetSettings() method that can be called by ResetUserControl.
// model for the settings
class SettingsManager
{
public event EventHandler SettingsChanged;
public async void ResetSettings()
{
await Windows.Storage.ApplicationData.Current.ClearAsync
(Windows.Storage.ApplicationDataLocality.Local);
// initialize all values to default values;
this._intializeValues();
if (this.SettingsChanged != null)
this.SettingsChanged(this, EventArgs.Empty);
}
}
HistoryStatistics and Calendar class should have view model that should listen for SettingsChanged event and update the properties exposed. Each page view (xaml) binds to the properties exposed by the respective view model. This will require some refactoring of current code.
Without that, ResetClick eventhandlers can be changed to SettingChanged event handlers and take required action. They need not call setting mgr to initialize values.
class HistoryStatistics
{
private void SettingsChanged(object sender, EventArgs e)
{
SettingsManager settingsManager = SettingsManager.Instance;
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
HTH.
Why does this never get called ?
propertyGrid.KeyDown += new KeyEventHandler(propertyGrid_KeyDown);
private void propertyGrid_KeyDown(object sender, KeyEventArgs e)
{
PoorLittleMethod(); //Never gets called
}
This seems to be the same for Mouse event
I'veread on some forums that PGrid is tricky on raising such events as it Inherits them from Control but does not really Raise them. is that true ? If yes, how to bypass that ?
EDIT 1:
As this seems to be "regular", I find it very light from MS not to specify this explicitely on the MSDN Reference of the propertyGrid class and leave events "as is" as if they were usable, whereas they are not. Tricky things like these are at least usually specified in "notes" inside the refs.
EDIT 2:
I am presently coding a workaround. I'll be posting it soon.
The PropertyGrid's KeyDown property is marked as Browsable(false) - presumably the conclusion we can take from this is that it is not supported in an of itself but is in fact present as a side-effect of its inheritance hierarchy.
Though, interestingly enough, its EditorBrowsable attribute (which is also a designer indicator, for Intellisense and the suchlike) is set as EditorBrowsableState.Advanced - where we would expect EditorBrowsableState.Never should the former presumption be true.
Some information from MSDN forums outlines the why of this situation:
From the tool UI Spy we can see the PropertyGrid is a just a panel and it consists of three Windows Controls. Our KeyDown event should be processed by the child control table.
The structure:
-"pane" "PropertyGrid"
--"pane" "Description Pane"
--"table" "Properties Window"
--"tool bar" "ToolBar"
The suggested solution (also provided in the MSDN link) to overcoming this is to use native system calls to retrieve window/control information, subclass NativeWindow and override the WndProc method to handle the events you like, KeyDown in this case.
You can override this from subclass of PropertyGrid to get some key info from windows message
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
CSharp PropertyGrid Events
// Property grid events can’t be easily subscribed to however there is way to get at the KeyUp event without impacting operation.
// Note: The KeyDown event can be subscribed to in the same manner but the propertygrid is NOT updated with the key presses.
// This code is added in hope it may help someone else solve the problem. It is not offered as a total solution.
// First define a class variable to indicate that events have been added.
private bool m_bPropertyGridEventsAdded = false;
public GlassInfoEntryPage(ViewBase view)
: base(view)
{
InitializeComponent();
// Subscribe to SelectedGridItemChanged
m_PropertyGrid.SelectedGridItemChanged += M_PropertyGrid_SelectedGridItemChanged;
}
// Now define a SelectedGridItemChanged Event Handler
private void M_PropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
int nXlocation;
int nYlocation;
PropertyGrid oPropertyGrid;
Control oControl;
if (m_bPropertyGridEventsAdded == false)
{
oPropertyGrid = (PropertyGrid)sender;
// Search the Property Grid for a PropertyGridView Control so events can be added to it
for (nXlocation = 0; nXlocation < oPropertyGrid.Width; nXlocation += 10)
{
for (nYlocation = 0; nYlocation < oPropertyGrid.Height; nYlocation += 10)
{
oControl = m_glassInfoPropertyGrid.GetChildAtPoint(new Point(nXlocation, nYlocation));
if (oControl != null)
{
if (oControl.GetType().ToString() == "System.Windows.Forms.PropertyGridInternal.PropertyGridView")
{
// Add Events here
oControl.Controls[1].KeyUp += MyCode_KeyUp;
m_bPropertyGridEventsAdded = true;
break;
}
}
}
if (m_bPropertyGridEventsAdded == true)
{
break;
}
}
}
}
// Handle the events
private void MyCode_KeyUp(object sender, KeyEventArgs e)
{
}