How to get notified after the event ends - c#

In my UWP app I am using DynamicOverflowItemsChanging event of a CommandBar my usecase is not very complex, I tried to solve another problem I had by using this event, see the answer of this post.
So as shown in the answer in the link I provided above, I am trying to invoke this event and sync the visibility of MoreButton now the problem is this event is fired when the secondary overflow menu of command bar doesn't have the item removed or added yet, so they still show the items which they had before the event was fired, but when this event is completed then transfer of items is also completed.
So in short I want to raise another event somehow or get notified when the DynamicOverflowItemsChanging completes its execution, so I can have the correct data and set the visibility of more button correctly. or in other words I want to implement a behaviour of DynamicOverflowItemsChanged event, which unfortunately doesn't exist in the api, so I am looking for an alternative way.
I know I can invoke another event right at the end (just before DynamicOverflowItemsChanging event is finished), but that way I still don't get the correct values, correct values only become available when this event finishes its execution. Like we can do with Task.Then() so when a task completes another can automatically start, so I want something like that here . any suggestions would be appreciated.
protected override void OnApplyTemplate()
{
var barr = (CommandBar)GetTemplateChild("MediaControlsCommandBar");
//the event to control the dynamicoverflow automatically.
barr.DynamicOverflowItemsChanging += (s, e) =>
{
if (_secondarycontrols.Items.Count == 0 && e.Action == CommandBarDynamicOverflowAction.AddingToOverflow)
_moreButton.Visibility = Visibility.Visible;
else if (_secondarycontrols.Items.Count == 1 && e.Action == CommandBarDynamicOverflowAction.RemovingFromOverflow)
_moreButton.Visibility = Visibility.Collapsed;
};//when this event finishes here I want to get notified.
//base implementation
base.OnApplyTemplate();
}

Warm greetings, fellow Microsoft Student Partner :-) .
The quick and dirty hack would be to add a Task.Delay to the end of the handler and hope the items will have changed until the delay is over. This is of course really ugly and error prone. I would suggest a different solution.
You already have access to the _secondarycontrols which is a CommandBarOverflowPresenter. This is very useful, because Items property has a VectorChanged event which is fired whenever an item is added, removed or changed. This means, you can actually use this event and move your logic inside it instead of using the DynamicOverflowItemsChanging event. You can then directly check for the number of items which will be accurate.

Related

Is it possible to fire ComboBox SelectedIndex Changed Event even when old and new index are same?

I have a scenario is which I need to fire the SelectedIndexChanged event of a winform's combox even when the old and new index is same.. I can not use SelectionChangeCommited because the values are being set programmatically .. and it wont get fired. Is it by any chance to force 'SelectedIndexChanged' to fire even when old and same index are same?
It seems wierd that you want the event to refire for the same item. It's probably because you just want to reexecute the event handler logic. Why dont you extract the SelectionChanged logic into a new method and call that one programmatically?
Nothing prevents you from calling event handler directly:
comboBox1_SelectedIndexChanged(comboBox1, new EventArgs()); // or (null, null)
But solution of atomaras is a better (nicer) way to do it.
I myself dislike to use standard components in more-less serious software. Instead I subclass all standard components from very beginning and adding functionality to them as soon as I need it without needs to change anything in the existing forms.
In this case I'd add a public event riser OnSelectedIndexChanged to execute event (to run code inside event handler programmatically).
combobox.selectedIndex = value;
combobox.selectedevent(null,null);

ListView with an empty SelectedItems , when DoubleClick handler is called

I have a WinForm app that has a ListView in it, with a DoubleClick event handler assigned to it.
Theoretically , only items are "clickable" , so it should be impossible to enter the event handler with no selected items, and so it is for 99% of cases.
However, every once in a while, I catch an exception of InvalidAgrument as my handler try to access list_view.SelectedItems[0], and there I see that it does actually empty.
When I try to reproduce, it takes an aggressive clicking session to do it. But it's done, I can sometimes see the cursor in the middle of a valid entity , which makes me suspect it might be some racing condition.
This can certainly go wrong, a double-click doesn't guarantee that an item is selected. It may also de-select an item, your code will crash. Short from adding the test to check that SelectedItems isn't empty, the possible better mouse trap is to find the exact item that was double-clicked. Use the MouseDoubleClick event instead so you get the mouse position, then use the ListView.HitTest() method. Like this:
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e) {
var item = ((ListView)sender).HitTest(e.Location);
if (item != null) {
// etc..
}
}

list.clear() is calling list.selectionchanged event

I am developing a Windows Phone app. There is a list which has to be cleared once a list item is selected from it.
I used Clear(), but it's giving me some exception.
Is list.Clear() calling list.SelectionChanged event internally?
How to solve this problem?
try detaching/attaching event
list.SelectionChanged -= yourevent;
list.Clear();
list.SelectionChanged += yourevent;
I will simply suggest to make changes to your SelectionChanged event to keep things in Sync.
private void SelectionChanged_Event()
{
if(!list.Any()) // Or any similar check to see if it contains anything
return;
// Then goes your rest of the code.
}
It should avoid any exception you are getting. However, you should have mentioned the exception so that we can analyze it further.
Not sure if this applies to your mobile environment, but it should be the same.
Set a Break on the selectionchanged event, and see if it does break into the event. My guess is that you are right and that it does trigger the selectionchanged event.
Write code in the selectionchanged event to check for the number of selected items, if none (I.e. we are not actively selecting anything in the list), exit the function.
In vb.net it would be:
If mylist.selecteditems.count = 0 then exit **sub/function** <- whichever applies

How can a control handle a Mouse click outside of that control?

I'm writing a custom control and I'd like the control to switch from an editing state to it's normal state when a user clicks off of the control. I'm handling the LostFocus event and that helps when a user tabs away or if they click on to another control that's Focusable. But if they don't click on something Focusable, it won't switch out of it's editing state. So I have two solutions in mind:
Walk up the tree to the top most element when it goes in to an editing state and add a handler for MouseDownEvent (and handle "handled" events). In the handler I'd kick the control out of it's editing state and remove the handler from the top most element. This seems like a bit of a hack, but it would probably work well.
Example code:
private void RegisterTopMostParentMouseClickEvent()
{
_topMostParent = this.FindLastVisualAncestor<FrameworkElement>();
if ( _topMostParent == null )
return;
_topMostParent.AddHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ), true );
}
private void UnRegisterTopMostParentMouseClickEvent()
{
if ( _topMostParent == null )
return;
_topMostParent.RemoveHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ) );
_topMostParent = null;
}
Use Mouse.PreviewMouseDownOutsideCapturedElement and add a handler to my control. In the handler I'd kick the control out of it's editing state. But I don't seem to get the event to fire. When does the Mouse.PreviewMouseDownOutsideCapturedElement get kicked off?
Example code:
AddHandler( Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler( EditableTextBlockPreviewMouseDownOutsideCapturedElementEvent ), true );
Just to clarify the answer provided about mouse focus - it was useful but I had to do some further digging + mucking about to get something that actually worked:
I was trying to implement something like a combobox and needed similar behaviour - to get the drop down to disapear when clicking on something else, without the control having knowledge of what something else was.
I had the following event for a drop down button:
private void ClickButton(object sender, RoutedEventArgs routedEventArgs)
{
//do stuff (eg activate drop down)
Mouse.Capture(this, CaptureMode.SubTree);
AddHandler();
}
The CaptureMode.SubTree means you only get events that are outside the control and any mouse activity in the control is passed through to things as normal. You dont have the option to provide this Enum in UIElement's CaptureMouse, this means you will get calls to HandleClickOutsideOfControl INSTEAD of calls to any child controls or other handlers within the control. This is the case even if you dont subscribe to the events they are using - full Mouse capture is a bit too much!
private void AddHandler()
{
AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl), true);
}
You would also need to hang on to + remove the handler at the appropriate points but I've left that out here for the sake of clarity/brevity.
Finally in the handler you need to release the capture again.
private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e)
{
//do stuff (eg close drop down)
ReleaseMouseCapture();
}
Capture the mouse.
When an object captures the mouse, all mouse related events are treated as if the object with mouse capture perform the event, even if the mouse pointer is over another object.
I usually get the parent window and add a preview handler, even if already handled. Sometimes when MouseCapture is not enough, this technique comes handy:
Window.GetWindow(this).AddHandler
(
UIElement.MouseDownEvent,
(MouseButtonEventHandler)TextBox_PreviewMouseDown,
true
);
I would approach this a different way - have the form that contains the control remove focus from the control when a user clicks on another part of the form.
Having the control actually loose focus is far cleaner than attempting to have the control "simulate" focus being lost in certain situations, when in fact it hasn't. Bear in mind that unless the control has really lost focus it will still accept things like keyboard input.

Issue in CheckedChanged event

I have a check box and I have subscribed for the CheckedChanged event. The handler does some operations in there. I check and uncheck the checkbox programmatically (ex: chkbx_Name.Checked = true), and the CheckedChanged event gets fired.
I want this event to be fired only when I manually check or uncheck it. Is there any way to avoid firing of this event when i check/uncheck it programmatically?
unsubscribe the event before you set:
check1.CheckChanged -= check1_CheckChanged;
then you can programmatically set the value without the checkbox firing its CheckChanged event:
check1.Checked = true;
then re-subscribe:
check1.CheckChanged += check1_CheckChanged;
[EDIT: March 29, 2012]
The problem with Tanvi's approach is you need to catch all source of manual check or uncheck. Not that there's too many(it's only from mouse click and from user pressing spacebar), but you have to consider invoking a refactored event from MouseClick and KeyUp(detecting the spacebar)
It's more neat for a CheckBox(any control for that matter) to be agnostic of the source of user input(keyboard, mouse, etc), so for this I will just make the programmatic setting of CheckBox really programmatic. For example, you can wrap the programmatic setting of the property to an extension method:
static class Helper
{
public static void SetCheckProgrammatically(
this CheckBox c,
EventHandler subscribedEvent, bool b)
{
c.CheckedChanged -= subscribedEvent; // unsubscribe
c.Checked = b;
c.CheckedChanged += subscribedEvent; // subscribe
}
}
Using this approach, your code can respond neatly to both user's mouse input and keyboard input via one event only, i.e. via CheckChanged. No duplication of code, no need to subscribe to multiple events (e.g. keyboard, checking/unchecking the CheckBox by pressing spacebar)
No. Those property change events fire whenever the property value changes, regardless of whether this was done by your code, by the control's own code or databinding. It's all the same code path, usually.
What you can do, however, if your event handler resides in the same class as the code that changes the property value, is to introduce a private boolean field in the class which you use as an indicator of whether the current property change is triggered by your code or by the user. After your change you simply reset it. The event handler would then look at the field and decide of whether it should do anything or not:
class Foo : Form {
private bool checkedProgrammatically = false;
void someMethod() {
// ...
checkedProgrammatically = true;
checkBox1.Checked = true;
checkedProgrammatically = false;
// ...
}
private void checkBox1_CheckChanged(object sender, EventArgs e) {
if (checkedProgrammatically) return;
// ...
}
}
I'm sorry I can't just comment on Michael Buen's answer due to my being new here (no reputation), but for what it's worth I strongly prefer his solution to Johannes Rössel's for a couple of reasons.
1) the checkedProgrammatically variable is a little too close to global for me. There's nothing to stop another method accidentally setting it to true, causing all your events to stop.
2) you could end up with a lot of variables depending on the number of events you're dealing with. It would be easy to change the wrong one and the results can be difficult to debug.
3) it's more obvious what you're doing when you unsubscribe then resubscribe. All the logic is right there, and you don't need to change your event handlers to exit early depending on certain conditions.
I've used both methods extensively and I find Michael's a lot easier in the long run.
You can use the MouseClick event and in that check for the checked state of the checkbox.
This way it wont be triggered programatically, it would only be called when the user manually checks or unchecks the checkbox.
You can set boolean variable before changing value programiticaly, and check than reset that variable in checkedchanged event

Categories

Resources