UWA - back button handling - c#

I've used backrequest event like below code and on appbar title back button or mobile device hardware button I should click twice on button till event work.
What should I do to it work with just one click?
SystemNavigationManager.GetForCurrentView().BackRequested += (sender, e) =>
{
bool handeled = e.Handled;
if (Frame.CanGoBack && !handeled)
{
handeled = true;
Frame.GoBack();
}
e.Handled = handeled;
};
if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
{
Windows.Phone.UI.Input.HardwareButtons.BackPressed += (sender, e) =>
{
bool handeled = e.Handled;
if (Frame.CanGoBack && !handeled)
{
handeled = true;
Frame.GoBack();
}
e.Handled = handeled;
};
}

I had the same issue. Every time I wanted to navigate back, I had to press the back button twice. Until I found out, that the SplitView was responsible for this problem. I had to close it, before navigating.
For example, if you want to move from Page1 to another page and then go back, use something like this on Page1:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
MySplitView.IsPaneOpen = false;
}
I hope it helps, even if you said that on a blank project (obvious without a Hamburger menu) the result was the same.

Related

How to make "Cancel" on iOS searchbar clickable when keyboard is not focused? [Xamarin Forms]

I am currently trying to adjust the Xamarin.Forms iOS SearchBar to show the "Cancel" button when I add text to the search bar (not through the keyboard, but a category click). I successfully did this with my code below. Now the issue is that, I want the "Cancel" button to be clickable once it shows up.
Currently I am doing the following:
Click my command that changes the Text of the searchbar -> works
Cancel button shows up -> works
Cancel button is clickable -> does not work. it is gray. I need to click the searchbar (so the keyboard shows up) to have it turn blue and clickable.
This is my code:
[assembly: ExportRenderer(typeof(CustomSearchBar), typeof(SearchBar_iOS))]
namespace Project.iOS.Renderers
{
public class SearchBar_iOS : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.SearchBar> e)
{
base.OnElementChanged(e);
var element = e.NewElement as CustomSearchBar;
if (Control != null && element != null)
{
this.Control.TextChanged += (s, ea) =>
{
//if (ea.SearchText == "")
this.Control.ShowsCancelButton = true;
};
this.Control.OnEditingStarted += (s, ea) => //when control receives focus
{
this.Control.ShowsCancelButton = true;
};
this.Control.OnEditingStopped += (s, ea) => //when control looses focus
{
this.Control.ShowsCancelButton = false;
};
Control.BackgroundColor = Color.Transparent.ToUIColor();
Control.Layer.CornerRadius = 10;
Control.ClipsToBounds = true;
Control.SearchBarStyle = UISearchBarStyle.Minimal;
}
}
Is there a call in my renderer that can force it to be clickable when text is added?
This was already discussed for iOS native here:
How do you keep the cancel button in the search bar enabled when the keyboard is dismissed?
However it appears that iOS does not want you messing with the behavior of the Cancel button otherwise they would have exposed it publicly. That said, try this in your custom renderer for the OnEditingStopped event (quick test on my end worked):
this.Control.OnEditingStopped += async (s, ea) => //when control looses focus
{
this.Control.ShowsCancelButton = false;
var searchBar = this.Control;
BeginInvokeOnMainThread(() =>
{
var cancelButton = searchBar.ValueForKey(new NSString("cancelButton")) as UIButton;
cancelButton.Enabled = true;
});
};
There is a risk of Apple rejection or other undiscovered issues, so don't yell at me if it does not work. :-)
Also, since the cancel button is not made publicly accessible with out getting to it via the ValueForKey method, Apple could change the key name at any time which would break this hacky workaround.

WPF WebBrowser disable clicking & typing

Is there a way to prevent users in clicking and typing in WPF WebBrowser? It appears to me that it is only possible to do this in WinForms.
Things that I've tried:
browser.IsEnabled = false; - didn't work, can still click (navigate) and type in text
browser.Focusable = false; - same
having overlay button, which would consume clicks and focus - WebBrowser is a special element, that is always on top of other elements
having another WebBrowser on top of the main one with blank page loaded and opacity set to 0% as an alternative to overlay button (3.) - WPF WebBrowsers do not properly handle opacity, didn't work
browser_MouseDown event with e.Handled = true; - the event is for some reason not called on mouse down
Is there something that I've missed or did wrong in my attempts?
Three events and Boolean did it for me.
bool BrowserIsLoaded = false;
private void Browser_LoadCompleted(object sender, NavigationEventArgs e)
{
BrowserIsLoaded = true;
}
private void Browser_Navigating(object sender, NavigatingCancelEventArgs e)
{
if(BrowserIsLoaded)
e.Cancel = true;
}
private void Browser_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (BrowserIsLoaded)
e.Handled = true;
}
When the browser has finished loading it triggers the LoadCompleted event. Set a Boolean then check that when trying to navigate to a new page when they try to type in a box.
If you don't want to use your own Boolean (I used it for other things so it made sense to me) you can just ask the browser if it's loaded when ever you need it:
private void Browser_Navigating(object sender, NavigatingCancelEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
if(wb.IsLoaded)
{
e.Cancel = true;
}
}

C# If Button IsEnabled, its triggering event on click

I have next issue, I am working on small c#-wpf application,
and on load I am disabling button which is ussualy used to do some action on click, and it looks like this:
public MainWindow()
{
InitializeComponent();
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
if (String.IsNullOrEmpty(password.Password))
{
btnActivate.IsEnabled=false;
}
}
and somewhere I am checking my password field, for example:
private void password_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key.Equals(Key.Enter))
{
if (password.Password == "drag0n")
{
btnActivate.IsEnabled = true;
}
else
{
btnActivate.IsEnabled = false;
}
}
}
And my problem is next, when user enter "drag0n" and press enter, button should be just enabled, but its not only enabled, its calling automatic his event _Click, I don't know why does that happening, because in that case, if my button is just enabled event _Click is also called, and if user clicks on that button, event is called again, so actually my event onclick is called twice.
My question is how can I stop calling my Click event if I set IsEnabled=true. When I set IsEnabled=true I just want it to be enabled for pressing and I don't want execute event _Click.
I want to execute event _Click only when my button is pressed as it should work and not on IsEnabled=true.
Thanks guys,
Cheers
On click event occurs when you press Enter key, because this button is the default control in a form.
If you don't want click event on Enter key, you should either make this button not default or not process Enter key pressing in your button click (e.Handled = true -> when Enter is pressed).
Or try to change your code:
private void password_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key.Equals(Key.Enter))
{
if (password.Password == "drag0n")
{
e.Handled = true; // add this line
btnActivate.IsEnabled = true;
}
else
{
btnActivate.IsEnabled = false;
}
}
}

Setting myButton.Enabled = true causes radiobutton's CheckedChanged handler to fire

I have absolutely no programmatic links or properties set such that my CheckedChanged fires as a result of anything except checking the radio button.
However, when I click a different, unrelated button, the button's click handler fires (this is expected). In this click handler, the button disables itself (it re-enables on a different button's click), which then triggers myRadioButton_CheckedChanged handle for an unrelated radiobutton fires.
The call stack that I'm seeing is essentially
myRadioButton_CheckedChanged (...)
myButton_Click(...)
Main(...)
The line in myButton_Click that is triggering the myRadioButton_CheckedChanged is apparently
myButton.Enabled = false;
The related code is:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
// L-R
if (radioButton1.Checked == true)
{
orientation_left = 3;
pictureBox2.Invalidate();
Debug.Print("left {0}", orientation_left);
}
}
private void select1_Click(object sender, EventArgs e)
{
Debug.Print("select1click");
if (select1Down == false)
{
// ... stuff
select1.Enabled = false; // Causing the CheckedChanged to fire
select2.Enabled = false;
select1Down = true;
}
}
Ok, got it.
Check the TabOrder on your Button and RadioButton.
Seems that when you disable the Button, the focus is shifted to the next control, which is probably your RadioButton, causing it to become checked.
On my test From, all I had to do was to make sure that the RadioButton's TabOrder was not right after the Button.
Cheers
EDIT:
This seems to be a known problem as I just found this MSDN thread: http://social.msdn.microsoft.com/Forums/windows/en-US/77fbec3b-1f63-42e1-a200-19b261b63794/the-radiobutton-clicked-event-is-fired-without-the-radio-button-beeing-clicked-?forum=winforms
Okay, it's kinda hacky but it works without changing anything to the tab order:
private void select1_Click(object sender, EventArgs e)
{
if (!select1Down)
{
// ... stuff
SendKeys.SendWait("{Tab}");
select1.Enabled = false;
select2.Enabled = false;
select1Down = true;
}
}

Track Bar Only fire event on final value not ever time value changes

I am working on a pretty basic C# visual studio forms application but am having some issue getting the track bar to act as I want it to so hoping someone in the community might have a solution for this.
What I have is a pretty basic application with the main part being a track bar with a value of 0 to 100. The user sets the value of the track to represent "the amount of work to perform" at which point the program reaches out to some devices and tells them to do "x" amount of work (x being the value of the trackbar). So what I do is use the track bars scroll event to catch when the track bars value has changed and inside the handler call out to the devices and tells them how much work to do.
My issue is that my event handler is called for each value between where the track bar currently resides and where ever it ends. So if it is slid from 10 to 30, my event handler is called 20 times which means I am reaching out to my devices and telling them to run at values I don't even want them to run at. Is there someway only to event when scroll has stopped happening so you can check the final value?
Just check a variable, if the user clicked the track bar. If so, delay the output.
bool clicked = false;
trackBar1.Scroll += (s,
e) =>
{
if (clicked)
return;
Console.WriteLine(trackBar1.Value);
};
trackBar1.MouseDown += (s,
e) =>
{
clicked = true;
};
trackBar1.MouseUp += (s,
e) =>
{
if (!clicked)
return;
clicked = false;
Console.WriteLine(trackBar1.Value);
};
For the problem #roken mentioned, you can set LargeChange and SmallChange to 0.
Try the MouseCaptureChanged event - that is the best for this task
A user could also move the track bar multiple times in a short period of time, or click on the track multiple times to increment the thumb over instead of dragging the thumb. All being additional cases where the value that registers at the end of a "thumb move" is not really the final value your user desires.
Sounds like you need a button to confirm the change, which would then capture the current value of the trackbar and send it off to your devices.
Try this with the trackbar_valuechanged event handler:
trackbar_valuechanged(s,e) {
if(trackbar.value == 10){
//Do whatever you want
} else{
//Do nothing or something else
}
}
I found a fairly reliable way to do this is to use a timer hooked up in the trackbar.Scroll event:
private Timer _scrollingTimer = null;
private void trackbar_Scroll(object sender, EventArgs e)
{
if (_scrollingTimer == null)
{
// Will tick every 500ms (change as required)
_scrollingTimer = new Timer()
{
Enabled = false,
Interval = 500,
Tag = (sender as TrackBar).Value
};
_scrollingTimer.Tick += (s, ea) =>
{
// check to see if the value has changed since we last ticked
if (trackBar.Value == (int)_scrollingTimer.Tag)
{
// scrolling has stopped so we are good to go ahead and do stuff
_scrollingTimer.Stop();
// Do Stuff Here . . .
_scrollingTimer.Dispose();
_scrollingTimer = null;
}
else
{
// record the last value seen
_scrollingTimer.Tag = trackBar.Value;
}
};
_scrollingTimer.Start();
}
}
I had this problem just now as I'm implementing a built in video player and would like the user to be able to change the position of the video but I didn't want to overload the video playback API by sending it SetPosition calls for every tick the user passed on the way to his/her final destination.
This is my solution:
First, the arrow keys are a problem. You can try your best to handle the arrow keys via a timer or some other mechanism but I found it more pain than it is worth. So set the property SmallChange and LargeChange to 0 as #Matthias mentioned.
For mouse input, the user is going to have to click down, move it, and let go so handle the MouseDown, MouseUp, and the Scroll events of the trackbar like so:
private bool trackbarMouseDown = false;
private bool trackbarScrolling = false;
private void trackbarCurrentPosition_Scroll(object sender, EventArgs e)
{
trackbarScrolling = true;
}
private void trackbarCurrentPosition_MouseUp(object sender, MouseEventArgs e)
{
if (trackbarMouseDown == true && trackbarScrolling == true)
Playback.SetPosition(trackbarCurrentPosition.Value);
trackbarMouseDown = false;
trackbarScrolling = false;
}
private void trackbarCurrentPosition_MouseDown(object sender, MouseEventArgs e)
{
trackbarMouseDown = true;
}
I had a similar problem, only with a range TrackBar Control. Same idea applies to this also, only it's easier for this case.
I handled the MouseUp Event on the TrackBar to launch the procedures I needed, only after you would let go of the mouse button. This works if you drag the bar to your desired position or just click it.
private void rangeTrackBarControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
YourProcedureHere();
}
i solved the problem for my application with two events:
catch the Trackbar-ValueChange-Event
whithin the value-change event disable the valuechange event and enable the MouseUp-Event
public MainWindow()
{
//Event for new Trackbar-Value
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
}
private void trackbar_ValueChanged(object sender, EventArgs e)
{
//enable Trackbar Mouse-ButtonUp-Event
trackbar.MouseUp += ch1_slider_MouseUp;
//disable Trackbar-ValueChange-Event
trackbar.ValueChanged -= ch1_slider_ValueChanged;
}
private void trackbar_MouseUp(object sender, EventArgs e)
{
//enable Trackbar-ValueChange-Event again
trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
//disable Mouse-ButtonUp-Event
trackbar.MouseUp -= trackbar_MouseUp;
//This is the final trackbar-value
textBox.AppendText(trackbar.Value);
}
ATTENTION: this works if the trackbar is moved by mose. It is also possible to move the trackbar by keyboard. Then futher code must be implemented to handle this event.

Categories