I'm trying to register an event to the MainPage.xaml.cs like this :
public partial class MainPage : PhoneApplicationPage
{
public static ICanvas CurrentCanvas;
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
//HERE I TRY TO REGISTER FOR MY EVENT
((WP8Canvas)CurrentCanvas).Redraw += WP8EventHandler_RedrawCanvas;
//HERE I TRY TO REGISTER FOR MY EVENT/
System.Threading.ThreadStart start = new System.Threading.ThreadStart(launchProcessA);
System.Threading.Thread t = new System.Threading.Thread(start);
t.Name = "ProcessA Thread";
t.Start();
}
/// <summary>
/// Listen to WP8Canvas repaint() methods
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void WP8EventHandler_RedrawCanvas(object sender, EventArgs e)
{
wpCanvas.InvalidateArrange();
Debug.WriteLine("Redraw Canvas Event");
}
}
WP8Canvas.cs
public class WP8Canvas : WP8Displayable, ICanvas
{
public Canvas canvas ;
public event EventHandler Redraw;
protected object reference;
public WP8Canvas(object reference)
{
this.reference = reference;
MainPage.CurrentCanvas = this;
Debug.WriteLine("WP8Canvas instance");
}
public void repaint()
{
RedrawCanvas();
}
/// <summary>
/// Raise event if repaint() method is hit
/// </summary
private void RedrawCanvas()
{
//Null check makes sure the main page is attached to the event
if (this.Redraw != null)
this.Redraw(new object(), new EventArgs());
}
}
Between my comment //HERE I TRY TO REGISTER FOR MY EVENT I try to register an non-instantiated object WP8Canvas but of course a null exception occurs. It's my Thread t who controls the creation of WP8Canvas object but this happens during run-time and I don't know when.
QUESTION : How can I register my WP8Canvas Redraw event to the MainPage without facing that null pointer exception.
If you have no control over the launchProcessA, then a way to reach this result is to use a property:
public WP8Canvas CurrentWP8Canvas
{
get
{
return this.CurrentCanvas as WP8Canvas;
}
set
{
this.CurrentCanvas = value;
value.Redraw += WP8EventHandler_RedrawCanvas;
}
}
Then you juste have to change your code so that the thread assigns the CurrentWP8Canvas property instead of CurrentCanvas
Edit: If you need it to be static, one way could be to store the event handler in a temporary static variable:
public static EventHandler RedrawCanvas { get; set; }
Then set it from MainPage's constructor:
RedrawCanvas = WP8EventHandler_RedrawCanvas;
Finally, declare CurrentWP8Canvas as static, and assign the event handler you stored:
public static WP8Canvas CurrentWP8Canvas
{
get
{
return CurrentCanvas as WP8Canvas;
}
set
{
CurrentCanvas = value;
value.Redraw += RedrawCanvas;
}
}
It should work. However, it's terribly wrong, for many reasons: thread synchronization issues, risks of memory leaks... At that point, you're supposed to conclude that you've reached a dead-end, backtrack, and consider redesigning your architecture.
Related
I am trying to create my own ContextMenuOpening event (Event ContextMenuOpening name should be same as FrameworkElement class) when I tried to trigger that event from Xaml page its throwing “Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type” but its works fine when I hook the event in code behind.
Please find the below code Snippet to reproduce issue and provide suggestion on this.
XAML
<local:ContextMenuEvetTest x:Name="menu" ContextMenuOpening="menu_ContextMenuOpening" />
Code Behind
#region Main Class
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//this.menu.ContextMenuOpening += menu_ContextMenuOpening;
}
void menu_ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e)
{
}
}
#endregion
#region Base Class
public class ContextMenuEvet : Control
{
public ContextMenuEvet()
{
}
public delegate void ContextMenuOpeningEventHandler(object sender, ContextMenuOpeningEventArgs e);
public new event ContextMenuOpeningEventHandler ContextMenuOpening;
internal void GetContextMenuOpeningEvent(ContextMenuOpeningEventArgs e)
{
if (ContextMenuOpening != null)
ContextMenuOpening(this, e);
}
}
#endregion
#region Derived Class
public class ContextMenuEvetTest : ContextMenuEvet
{
static ContextMenuEvetTest()
{
}
}
#endregion
#region EventsArgument
public class ContextMenuOpeningEventArgs : CancelEventArgs
{
}
#endregion
Thanks in advance.
Jeyasri M
Change your event definition to :
public new event ContextMenuEventHandler ContextMenuOpening
{
add
{
base.AddHandler(FrameworkElement.ContextMenuOpeningEvent, value);
}
remove
{
base.RemoveHandler(FrameworkElement.ContextMenuOpeningEvent, value);
}
}
and remove this,
if (ContextMenuOpening != null)
ContextMenuOpening(this, e);
and use,
internal void GetContextMenuOpeningEvent(ContextMenuEventArgs e)
{
base.OnContextMenuOpening(e);
}
i'm learning MVVM pattern with wpf and i'm trying to create a simple splashscreen for loading applications.
I have a simple class called Loading with two property which are bounded to my interface.
public class Loading : INotifyPropertyChanged
{
/// <summary>
/// Define current status value from 0 to 100.
/// </summary>
private int _currentStatus;
/// <summary>
/// Define current status text.
/// </summary>
private string _textStatus;
/// <summary>
/// Define constructor.
/// </summary>
public Loading(int status, string statusText)
{
_currentStatus = status;
_textStatus = statusText;
}
public int CurrentStatus
{
get { return _currentStatus; }
set
{
_currentStatus = value;
OnPropertyChanged("CurrentStatus");
}
}
public string TextStatus
{
get { return _textStatus; }
set
{
_textStatus = value;
OnPropertyChanged("TextStatus");
}
}
#region Interfaces
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
From my ctor ViewModel i instanciate this model
Loading = new Loading(0, "Loading...");
and run a new thread calling the function GetSystemInfo() which perform some stuff in order to load some information.
Thread systemInfo = new Thread(GetSystemInfo);
systemInfo.IsBackground = true;
systemInfo.Start();
I'm updating the ui from GetSystemInfo() with
Loading.TextStatus = "Loading User Information...";
Loading.CurrentStatus = 50;
So far so good.. the thread is correctly updating the ui but the problem is that i wish to close this splashcreen and open a new window when the loading is complete but i'm unable to check if the thread is complete or at least i don't found a way to do that.
Is there any way i can solve this problem?
Thanks.
You achieve this rather easily by using the Task class (via Task Parallel Library) with a combination of async-await.
What happens when you await on a Task is that the control is yielded back to the caller. In your case, the caller comes from the UI thread, so the control will return to the UI message loop, keeping you app responsive. Once the thread finishes it's work, it will return to the next line after the await, where you can then open the splash screen.
It will look like this:
public async void MyEventHandler(object sender, EventArgs e)
{
await Task.Run(() => GetSystemInfo());
// Here, you're back on the UI thread.
// You can open a splash screen.
}
I have three objects ObjectA has an ObjectB, ObjectB has an ObjectC. When ObjectC fires an event I need ObjectA to know about it, so this is what I've done...
public delegate void EventFiredEventHandler();
public class ObjectA
{
ObjectB objB;
public ObjectA()
{
objB = new ObjectB();
objB.EventFired += new EventFiredEventHandler(objB_EventFired);
}
private void objB_EventFired()
{
//Handle the event.
}
}
public class ObjectB
{
ObjectC objC;
public ObjectB()
{
objC = new ObjectC();
objC.EventFired += new EventFiredEventHandler(objC_EventFired);
objC.FireEvent();
}
public event EventFiredEventHandler EventFired;
protected void OnEventFired()
{
if(EventFired != null)
{
EventFired();
}
}
private void objC_EventFired()
{
//objC fired an event, bubble it up.
OnEventFired();
}
}
public class ObjectC
{
public ObjectC(){}
public void FireEvent()
{
OnEventFired();
}
public event EventFiredEventHandler EventFired;
protected void OnEventFired()
{
if(EventFired != null)
{
EventFired();
}
}
}
Is this the proper way to handle this, or is there a better way? I don't want ObjectA to know about ObjectC at all, only that it raised an event.
Another approach, is to wrap it using add/remove:
public class ObjectB
{
ObjectC objC;
public ObjectB()
{
objC = new ObjectC();
}
public event EventFiredEventHandler EventFired
{
add { this.objC.EventFired += value; }
remove { this.objC.EventFired -= value; }
}
}
That's the way I do it. however I would recommend change your firing mechanism to this to make it thread safe
protected void OnEventFired()
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent();
}
}
This keeps it from failing if EventFired becomes null between the null check and the firing.
Also it is somewhat of a standard to follow the EventHandler pattern for your event delegates.
protected virtual void OnEventFired(EventArgs e)
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent(this, EventArgs.e);
}
}
I was wrong about the threadsafe pattern, here is the full threadsafe event pattern
/// <summary>
/// Delegate backing the SomeEvent event.
/// </summary>
SomeEventHandler someEvent;
/// <summary>
/// Lock for SomeEvent delegate access.
/// </summary>
readonly object someEventLock = new object();
/// <summary>
/// Description for the event
/// </summary>
public event SomeEventHandler SomeEvent
{
add
{
lock (someEventLock)
{
someEvent += value;
}
}
remove
{
lock (someEventLock)
{
someEvent -= value;
}
}
}
/// <summary>
/// Raises the SomeEvent event
/// </summary>
protected virtual OnSomeEvent(EventArgs e)
{
SomeEventHandler handler;
lock (someEventLock)
{
handler = someEvent;
}
if (handler != null)
{
handler (this, e);
}
}
As other answers have stated, this is they way to do it.
But you can go beyond!!! I've just implemented a good data structure on it, and it's like to give you a spin on it.
Would be nice to have an automatic event bubbling? You could implement it using Reflection. My way is to define an Interface/Base class which declares an event (or a set of events). Then, the parameterless constructor of a base class will iterate other its properties/fields, and register automatically the members events for event propagation.
There are some restriction on design, but if you have a deep structure and/or many (structured) events, it could be nice to have everything setup without any additional line of code.
An initial base class could be:
class BaseObject {
public BaseObject() {
FieldInfo[] fInfos = this.GetType().GetFields(...);
foreach (FieldInfo fInfo in fInfos) {
object fInfoValue = fInfo.GetValue(this, null);
if (fInfoValue is BaseObject) {
BaseObject bMemberObject = (BaseObject)fInfoValue;
bMemberObject.MyEvent += new EventHandler(delegate() {
if (this.MyEvent != null)
MyEvent();
});
}
}
public event MyEvent = null;
}
Of course, as already suggested, follow the event delegate delegate(object sender, EventArgs args) (I've used a simpler event for clarity).
Naturally, is implicit that you classes A, B and C derives directly from BaseObject.
Note that any logic could be implemented to bind structured events (you could be the nested event registration using the name and/or other reflected properties.
Can anyone explain to me what the following line of C# code does?
public event EventHandler<DataEventArgs<BusinessEntities.Employee>> EmployeeSelected = delegate { };
The bit that's really got me stumped is the delegate { } piece at the end. For a bit more context, the sample from the EmployeesListView.xaml.cs in the ViewInjection sample that ships with PRISM 2. The full class definition is shown below:
/// <summary>
/// Interaction logic for EmployeesListView.xaml
/// </summary>
public partial class EmployeesListView : UserControl, IEmployeesListView
{
public EmployeesListView()
{
InitializeComponent();
}
public ObservableCollection<BusinessEntities.Employee> Model
{
get { return this.DataContext as ObservableCollection<BusinessEntities.Employee>; }
set { this.DataContext = value; }
}
public event EventHandler<DataEventArgs<BusinessEntities.Employee>> EmployeeSelected = delegate { };
private void EmployeesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
BusinessEntities.Employee selected = e.AddedItems[0] as BusinessEntities.Employee;
if (selected != null)
{
EmployeeSelected(this, new DataEventArgs<BusinessEntities.Employee>(selected));
}
}
}
}
This bit:
delegate {}
just creates a "no-op" delegate of the appropriate type. That delegate is then assigned to the backing variable for the event. It's a simple way to avoid having to do null checks when raising an event - you always have at least one handler, which is the no-op handler.
It means that this code can be simple:
EmployeeSelected(this, new DataEventArgs<BusinessEntities.Employee>(selected));
Instead of:
EventHandler<DataEventArgs<BusinessEntities.Employee>> handler =EmployeeSelected;
if (handler != null)
{
handler(this, new DataEventArgs<BusinessEntities.Employee>(selected));
}
It's setting it to an anonymous method that does nothing basically. Why I'm not sure, maybe to avoid a check or something but I would consider that quite sloppy.
Say I have a box that says ENABLED or DISABLED.
How can I make the text vary depending on a state?
public void CheckBox1CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked) {
checkBox1.Text = "Enabled";
}
else {
checkBox1.Text = "Disabled";
}
}
box.Text = (box.Enabled ? "ENABLED" : "DISABLED");
If I understand correctly, you are asking how to have a label or some other bit of UI text automatically update to reflect a "state variable". This is just one way to accomplish what you're describing:
I would do it by having a central state object which implements INotifyPropertyChanging and INotifyPropertyChanged. When your application initializes, attach event handlers to the events those interfaces expose, and one of those event handlers can change the text of the label when property (Foo) changes.
public class State : INotifyPropertyChanging, INotifyPropertyChanged
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanging(PropertyChangingEventArgs e)
{
if (this.PropertyChanging != null)
{
this.PropertyChanging(this, e);
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, e);
}
}
public bool Foo
{
get
{
return foo;
}
set
{
if (value != foo)
{
this.OnPropertyChanging(new PropertyChangingEventArgs("Foo"));
foo = value;
this.OnPropertyChanged(new PropertyChangedEventArgs("Foo"));
}
}
}
private bool foo = false;
}
protected void HandleStateChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Foo")
{
box.Text = state.Foo ? "Enabled" : "Disabled";
}
}
What jeffamaphone said, but I should add that any time that state changes you will have to make sure to run that same code. The easiest way to insure this happens is by binding the box.Text property to the state object that you are interested in. That way, any change made to the object is immediately reflected in the text.
This blog post
helped me get started with data binding.... because I love FAQs.
The last few months I have been going with a slightly lighter weight solution than implementing a whole class to manage state. I usually define an enum which indicates the types of states available in the UI, then I have a function that makes changes to the UI, based on the state selected. This approach has been very successful, and not too heavy in terms of the amount of code needed to be written.
If I want to know what states are available in the UI, I can check the values of the enum.
public enum SystemState
{
/// <summary>
/// System is under the control of a remote logging application.
/// </summary>
RemoteMode,
/// <summary>
/// System is not under the control of a remote logging application.
/// </summary>
LocalMode
}
public interface IView
{
void SetState(SystemState state);
}
//method on the UI to modify UI
private void SetState(SystemState state)
{
switch (state)
{
case SystemState.LocalMode:
//for now, just unlock the ui
break;
case SystemState.RemoteMode:
//for now, just lock the ui
break;
default:
throw new Exception("Unknown State requested:" + state);
}
}
//now when you change state, you can take advantage of intellisense and compile time checking:
public void Connect()
{
SetState(SystemState.RemoteMode);
}