I have an element that I want to become highlighted when navigated to with a D-pad and respond to an "enter" button. I assumed I could do this with a focused element and am trying to set up my ContentView to handle such interaction.
The ContentView class inherits from VisualElement and has a Focus() method. The documentation states that for the Focus() method to work, the "[element] must be able to receive focus."
How can I make an element "able to receive focus"? It doesn't appear to work in UWP or Tizen with this bare-bones example. Tabbing, clicking, arrow keys, programmatically setting the focus... Nothing sets IsFocused to true, and my callback is never called.
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace MyProject.Components
{
public class FocusMe : ContentView
{
public FocusMe ()
{
Content = new StackLayout {
Children = {
new Label { Text = "Welcome to Xamarin.Forms!" }
}
};
Focused += FocusMe_Focused;
Task.Run(async () => {
await Task.Delay(5000);
Focus(); // false
_ = IsFocused; // false
});
}
private void FocusMe_Focused(object sender, FocusEventArgs e)
{
// never called
}
}
}
Can a ContentView receive focus?
Base on the testing, ContentView will not receive Focused event. However, Frame layout could receive focused event, and frame inherits from ContentView, you could use Frame to replace. Please note, you need to place focusable control in it such as button.
If you work on Tizen TV, How about check TV.UIControls, it is a extension library for TV applications
If do you want to react a key event on a view, I recommend to use ContentButton view on TV.UIControls
It is based on ContentView but works like a button
Here is a guide
https://samsung.github.io/Tizen.TV.UIControls/guides/ContentButton.html
Related
How to block UI in Caliburn.Micro?
public async void AcceptButton()
{
await this.httpDataService.Register(account);
Show.SuccesBox(alert);
this.TryClose();
}
How to wait for end of Task in my ViewModel by blocking View?
EDIT
i added binding on my button in xaml:
IsEnabled="{Binding isEnabled}"
Then, my VM:
bool isEnabled {get;set;}
public async void AcceptButton()
{
this.isEnabled = false;
await this.httpDataService.Register(account);
Show.SuccesBox(alert);
this.TryClose();
}
In this case, AcceptButton is always unactive IsEnabled=false. How to trigger false only on button click?
because i dont want to user double-tap "Send form" button
The standard way of doing that is just disabling the button. Or, if you want to disable the entire form, then disable the entire window:
public async void AcceptButton()
{
this.IsEnabled = false;
await this.httpDataService.Register(account);
Show.SuccesBox(alert);
this.TryClose();
}
You should add the IsEnabled property to your view model class and then bind it to the IsEnabled property of the view.
Disabling the window is nicer to the user than an unresponsive application, because this approach allows the user to minimize it or move it out of the way if it is taking an unexpectedly long time.
I when I press a button in view #1 (for example "PurpleFruitBtn") and I want to change the text in another view down the line (after a few other screens of other things) to display "Selection: Grape."
Have tried a few things, but they don't work.
How would more experienced people that know what they are doing do it?
Thanks,
A humbled kid who knows more and more that he doesn't know much.
You can define a string variable in View#2, and then put it in View#1 when you're switching to View#2,like this
enter image description here
When the page switch is complete, the label on the second page takes the variable of PhoneNumbers and displays it.
You can define a common class for transferring data between views:
using System;
namespace XamarinIosDataPass {
public class CommonClass {
public static string value;
}
}
Then when in view1, you update data when button is clicked:
partial void BtnSend_TouchUpInside(UIButton sender) {
CommonClass.value = txtInput.Text;
}
And update the lable in View2 based on value of the Common class:
public override void ViewDidLoad() {
base.ViewDidLoad();
lblDisplay.Text = CommonClass.value;
}
Please refer this link for more details.
Happy coding!
You can also use NSNotification to send message and pass value between two views.
in View #1
post the notification when you want to change the label in view#2
UIButton button = new UIButton(new CGRect(100, 300, 100, 50));
button.SetTitle("PurpleFruit",UIControlState.Normal);
button.SetTitleColor(UIColor.White, UIControlState.Normal);
button.BackgroundColor = UIColor.Blue;
button.TouchUpInside += (sender, e) =>
{
NSDictionary dic =NSDictionary.FromObjectAndKey(new NSString("value"),new NSString(button.TitleLabel.Text)) ;
NSNotification notification = NSNotification.FromName("ChangeValue",null,dic); //pass the string as a parameter
NSNotificationCenter.DefaultCenter.PostNotification(notification);
};
in view #2
Register the notification in the method ViewWillAppear
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
NSNotificationCenter.DefaultCenter.AddObserver(this,new Selector("ChangeValue:"),new NSString("ChangeValue") ,null);
}
[Export("ChangeValue:")]
public void ChangeValue(NSNotification notification)
{
Console.Write(notification.UserInfo.ObjectForKey(new NSString ("value")));
// now you can change the label.text
}
Notice :the name of notification must be same (just like ChangeValue in above code). Before posting you should register the notification firstly.Otherwise,view #2 can't receive the notification.
For more details about NSNotification you can refer to here
We are internationalizing a mobile app my team is developing, and I noticed the "Cancel" button in the SearchBar is not translating (everything else is translating just fine) - it always says "Cancel" in English no matter what language I change the iPad simulator to. If I can set the text myself, then I can ensure it's internationalized properly. So...
How do I change the "Cancel" button text on a Xamarin.Forms SearchBar? I've tried a custom renderer, but am having difficulty targeting the Cancel button subview. This answer seems to do a great job of explaining how to do that in Objective C, but I'm having trouble translating it into C# within the Xamarin.Forms framework.
Create a new custom renderer for iOS. Something like CustomSearchBarRenderer and subclass the Xamarin's original SearchBarRenderer
public class CustomSearchBarRenderer : SearchBarRenderer { }
I'd probably try to override OnElementChanged method and set the custom title after the base class has done all the work. Like this:
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
var cancelButton = Control.FindDescendantView<UIButton>();
cancelButton.Title = "Whatever";
}
Edit: Please be aware that the cancelButton might get recreated at some point so you might have to set the title at some other point too. However, this should be a good starting point.
You can also take a look at the current SearchBarRenderer implementation here.
I combined the answers and set the button text on each event which is needed. I also fixed the showing and hiding of the cancel button (see here):
using FestivalHolledauApp.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using System.Linq;
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
namespace FestivalHolledauApp.iOS
{
public class CustomSearchBarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
// Fixing Cancel button
if (e.NewElement != null)
{
this.Control.TextChanged += (s, ea) =>
{
this.Control.ShowsCancelButton = true;
SetCancelButtonText();
};
this.Control.OnEditingStarted += (s, ea) => //when control receives focus
{
this.Control.ShowsCancelButton = true;
SetCancelButtonText();
};
this.Control.OnEditingStopped += (s, ea) => //when control looses focus
{
this.Control.ShowsCancelButton = false;
};
}
}
private void SetCancelButtonText()
{
var cancelButton = Control.Descendants().OfType<UIButton>().FirstOrDefault();
if (cancelButton != null)
{
cancelButton.SetTitle("Schließen", UIControlState.Normal);
}
}
}
}
I've come over the same issue with ...
the "Cancel" button in a UISearchBar
the "Back" button to prior pages without title
context menu actions like "Cut", "Copy" and "Paste"
the "Done" buttons on date pickers and multiline editors
Everything else I got localized with resource based localization.
There are a lot of hacks out there finding the native buttons and setting texts manually but I knew this was not the way it was meant to be. So I digged deeper and found the following excellent article from Gerald Versluis:
https://blog.verslu.is/xamarin/xamarin-forms-xamarin/localization-default-ios-controls/
For me, this just meant to add the following block to my Info.plist:
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>de</string>
</array>
With this, iOS automatically translated all the UI elements for the current system culture (without adding these text to any resource files).
I am not very experienced using Behaviors, but so far they have come in handy to be able to execute code from the ViewModel but still triggering the actions from the View.
In my current scenario, I have a TextBox that appears when a Button is clicked. I would like to then set the focus of that TextBox after the Button has been clicked.
Previously, I have been able to set the focus using an EventTriggerBehavior like so:
<core:EventTriggerBehavior>
<behaviors:FocusAction />
</core:EventTriggerBehavior>
However, this will only suffice if I want to set the focus of that control when the View is loaded. In this case, the TextBox isn't visible at that time, and actually, the focus goes to a different TextBox initially.
Is there a way to set the focus of a control from the ViewModel? This is a WinRT 8.1 application, but will be being ported to Windows 10 Universal in the future.
EDIT
The answer here looks like it would do what I am looking for, but when I try it I get an error:
Cannot resolve symbol 'UIPropertyMetadata'
From what I can tell, that class exists in the System.Windows namespace, but even with a using System.Windows; I still get the same error. I have also tried new System.Windows.UIPropertyMetadata(null, ElementToFocusPropertyChanged) as well, but that doesn't make a difference either. Is that class not available in WinRT?
I was able to get it to work by slightly modifying the answer linked to in my original question. For anyone looking to accomplish this in a WinRT application, here is the modified code:
public class EventFocusAttachment
{
public static Control GetElementToFocus(Button button)
{
return (Control)button.GetValue(ElementToFocusProperty);
}
public static void SetElementToFocus(Button button, Control value)
{
button.SetValue(ElementToFocusProperty, value);
}
public static readonly DependencyProperty ElementToFocusProperty =
DependencyProperty.RegisterAttached("ElementToFocus", typeof(Control),
typeof(EventFocusAttachment), new PropertyMetadata(null, ElementToFocusPropertyChanged));
public static void ElementToFocusPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var button = sender as Button;
if (button != null)
{
button.Click += async (s, args) =>
{
var control = GetElementToFocus(button);
if (control != null)
{
await Task.Delay(100);
control.Focus(FocusState.Programmatic);
}
};
}
}
}
I had to add a small delay because the TextBox that I am focusing on is not visible until after the button is pressed, so it wasn't working without the delay. Also, I had to change the UIPropertyMetadata to simply PropertyMetadata, and add async to the lambda expression to allow for the await Task.Delay(100);
This is the image of the design window:
Here is the MainForm.Designer.cs file:
namespace SamsCSharp24
{
partial class ImeObrasca
{
// irrelavent code is omitted, only event subscriptions are left
private void InitializeComponent()
{
// irrelavent code is omitted for brewity
//
// SelectPicture
//
this.SelectPicture.Paint += new System.Windows.Forms.PaintEventHandler(this.SelectPicture_Paint);
this.SelectPicture.Click += new System.EventHandler(this.SelectPicture_Click);
//
// Quit
//
this.Quit.Click += new System.EventHandler(this.Quit_Click);
//
// PictureBox
//
this.PictureBox.MouseLeave += new System.EventHandler(this.PictureBox_MouseLeave);
this.PictureBox.MouseEnter += new System.EventHandler(this.PictureBox_MouseEnter);
//
// btnOptions
//
this.btnOptions.Click += new System.EventHandler(this.btnOptions_Click);
//
// timerClock
//
this.timerClock.Tick += new System.EventHandler(this.timerClock_Tick);
}
#endregion
}
}
Here is the MainForm.cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SamsCSharp24
{
public partial class ImeObrasca : Form
{
public ImeObrasca()
{
InitializeComponent();
// when uncommenting below line, window is not seen in taskbar
// this.ShowInTaskbar = false;
}
// other code is omitted for brewity
private void SelectPicture_Paint(object sender, PaintEventArgs e)
{
// just for fun, change color of a button to light blue
SelectPicture.BackColor = Color.Azure;
}
private void timerClock_Tick(object sender, EventArgs e)
{
// when timer ticks, change label's text into current time of day
staticClock.Text = "Current time of day: " +
DateTime.Now.Hour.ToString() + " : " +
DateTime.Now.Minute.ToString() + " : " +
DateTime.Now.Second.ToString();
}
}
}
Timer control has following properties set via designer:
Enabled = true;
Interval = 1000
Name = timerClick
Tick (event) = timerClock_Tick
As for label, here are the properties also set with designer:
BorderStyle = FixedSingle
Name = staticClock
Autosize = false
Text =
Other properties are default or irrelevant ( like Location or Size )
PROBLEM:
When I run the application ( in Debug mode ), window appears with properly placed controls and with proper look. Every other part of the code works successfully ( picture opening / drawing etc ) but the label remains empty, as initially set in the designer.
After I minimize / maximize the window, the label text is set correct. I have tried to move the part of the window with label "out" of the screen and get it back to see what happens. The text in the label was changed sometimes -> it didn't update correct.
MY EFFORTS TO SOLVE THE PROBLEM:
This is my first time trying out C# and WinForms so I have tried to find some online documentation on timers.
After examining .Designer.cs file I have found out that the timer from toolbox belongs to System.Windows.Forms.Timer class. I found nothing there to help me, since in Remarks section is stated that setting property Enabled to true starts the timer, and setting it to false stops it.
I have tried to put simple message box, and it started popping properly when the window was minimized. When window is in normal state nothing showed, but other parts of the program worked well ( picture opening / drawing / etc ).
After trying to Google for solution / searching here on SO, I have found no concrete solution ( although some suggestions were made, but as I said, they weren't helpful to me ).
QUESTION:
How to modify timer's tick handler, so label's text can be modified every second?
What am I doing wrong?
As Hans Passant stated in one of the comments, "Paint event handlers should only paint, they should never change properties that cause the Paint event to be fired again. Such shenanigans cause the UI thread to burn 100% core, never getting to dispatch the low-priority synthesized messages. Like WM_TIMER. Minimizing the window stops that, temporarily."