PhoneTextBox and LengthIndicatorVisible bug - c#

What I need to achieve is very simple. I have the following PhoneTextBox in a Windows Phone 8 application. When the TextBox has focus I need the LengthIndicatorVisible to be true and when it loses focus i don't want it there.
<toolkit:PhoneTextBox x:Name="TextBox1" MaxLength="480" GotFocus="TextBox1_GotFocus" LostFocus="TextBox1_LostFocus"/>
The focus methods are as follow:
private void TextBox1_GotFocus(object sender, RoutedEventArgs e)
{
TextBox1.LengthIndicatorVisible = true;
TextBox1.TextWrapping = TextWrapping.Wrap;
}
private void TextBox1_LostFocus(object sender, RoutedEventArgs e)
{
TextBox1.LengthIndicatorVisible = false;
TextBox1.TextWrapping = TextWrapping.NoWrap;
}
When it gets focused and I type something the Length Indicator is displayed as it should. Now when it loses its focus even though the LostFocus() method is being called the Length Indicator remains.
Also if I put an ActionIcon the textbox size due to TextWrapping gets bigger but when the text is cleared it does NOT return to its default size (height actually)
I have searched around for similar behavior but it is said to have been fixed on the latest release (the one i use - Toolkit).
Anyone has a clue of what is wrong here?
Thanks in advance.

Related

WPF Frame.Navigate triggering multiple events

I'm a fairly new to WPF and C#.
I have a frame component on my main window and 4 buttons next to it that navigate to different views in the frame. Within one the the views there is a DataGrid that has a SelectionChanged event which makes an SQL call to a database that fetches records, whose data is then used to populate a list of custom objects (these relate to the selected item on the DataGrid).
Anyways, the problem I have is that from time to time multiple calls (2 or 3) to the SelectionChanged event are being triggered at the same time for a single selection change (mouseclick) on the DataGrid.
The navigation button click events on the main window all look like this:
private void btn_MyDesk_Click(object sender, RoutedEventArgs e)
{
MainFrame.Navigate(new Uri("/Views/MyDeskView.xaml", UriKind.Relative));
}
private void btn_AllOrders_Click(object sender, RoutedEventArgs e)
{
MainFrame.Navigate(new Uri("/Views/AllOrdersView.xaml", UriKind.Relative));
}
After some experiementation, I've found that the bug only happens after changing views away from the view with the DataGrid, and then changing back to it (but not always). When the bug appears the number of calls generally corresponds to the number of times I had switched views. Furthermore, the bug will simply vanish if leave the program alone for a minute or two. This makes me suspect that there multiple instances of the DataGrid view lingering like ghosts in memory and duplicating event calls until they are cleaned up by a garbage collector.
Should I be cleaning something up each time I switch views, or am I looking in the wrong place?
Thank you in advance for any help.
Edit: In answer to #Peter Moore
I subscribe to the event in the DataGrid declaration within the views XAML: SelectionChanged="dtg_MyDeskOrderGrid_SelectionChanged"
Edit: This is the sequence that happens on a selection change in the data grid. It includes several UI changes while the SQL records for the new selection are retrieved and displayed on a second DataGrid (dtg_MyDeskOrderItems). While the SQL call is being made, the relevant controls are disbaled and a semi-transparent panel (bdr_DGLoadingPanel) is moved on screen to cover them and display a loading animation. When the work is done, the work area is re-enabled and the loading panel moved off screen. Focus is also returned to the main "order" Datagrid.
dtg_MyDeskOrderGrid: This is the main DataGrid showing all "Orders"
dtg_MyDeskOrderItems: This is a secondary DataGrid that is updated to show all "Items" in the selected order.
private void dtg_MyDeskOrderGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CurrSelectedOrder = (Order_class)dtg_MyDeskOrderGrid.SelectedItem;
if (CurrSelectedOrder.ItemList == null)
{
if (NowWorking == false)
{
NowWorking = true;
bdr_DGLoadingPanel.Margin = new Thickness(2);
dtg_MyDeskOrderGrid.IsEnabled = false;
bdr_FilterPanel.IsEnabled = false;
bdr_DGLoadingPanel.Focus();
img_LoadingCircle.RenderTransform = rt;
img_LoadingCircle.RenderTransformOrigin = new Point(0.5, 0.5);
da.RepeatBehavior = RepeatBehavior.Forever;
rt.BeginAnimation(RotateTransform.AngleProperty, da);
bdr_DGLoadingPanel.UpdateLayout();
worker.RunWorkerAsync();
}
}
else
{
dtg_MyDeskOrderItems.ItemsSource = null;
dtg_MyDeskOrderItems.ItemsSource = CurrSelectedOrder.ItemList;
dtg_MyDeskOrderItems.Items.Refresh();
}
}
private void worker_DoWork(object? sender, DoWorkEventArgs e)
{
DatabaseConnection DBConn9 = new DatabaseConnection();
DBConn9.FillOrderItems(CurrSelectedOrder);
}
private void worker_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
{
this.Dispatcher.Invoke(() =>
{
dtg_MyDeskOrderItems.ItemsSource = null;
dtg_MyDeskOrderItems.ItemsSource = CurrSelectedOrder.ItemList;
dtg_MyDeskOrderItems.Items.Refresh();
bdr_DGLoadingPanel.Margin = new Thickness(1000, 2, 2, 2);
rt.BeginAnimation(RotateTransform.AngleProperty, null);
dtg_MyDeskOrderGrid.IsEnabled = true;
bdr_FilterPanel.IsEnabled = true;
// The following work-around and accompanying GetDataGridCell function were used to give keyboard focus back to the datagrid to make navigation with arrow keys work again.
// It appears keyboard focus is not returned to the Datagrid cells when using the Datagrid.focus() method.
Keyboard.Focus(GetDataGridCell(dtg_MyDeskOrderGrid.SelectedCells[0]));
NowWorking = false;
});
}
Edit...
Following the advice of the commentors, I was able to fix the bug by unsubscribing from the event in the Unloaded event for the view containing the DataGrid:
private void uct_MyDeskView_Unloaded(object sender, RoutedEventArgs e)
{
dtg_MyDeskOrderGrid.SelectionChanged -= dtg_MyDeskOrderGrid_SelectionChanged;
}
However, I was not able to reproduce the bug using a barebones testing project.
The UI in the original project is quite heavy, so I'm wondering if it's not the old view and events lingering in memory as this seems to fit the behavior of the bug & fix (Only occuring when I navigate away and back causing a new view to be created, multiple event triggers corresponding to the number of times I navigated away, and then finally the bug vanishing of its own accord after a moment or two).
I won't be settling on this as a final solution and instead will learn about ways I can reuse instances of my views (as suggested by Bionic) instead of recreating them. The reason for this is, if the SelectionChanged event is getting multiple triggers from old view instances, then it is likely other events will suffer from the same bug. This would be bad.
#BionicCode If you are still around, could you repost your initial comment as a solution so I can mark it answered?
Thank you to everyone for all the help and education. ^_^
Following the advice of the commentors, I was able to initially fix the bug by unsubscribing from the event in the Unloaded event for the view containing the DataGrid:
private void uct_MyDeskView_Unloaded(object sender, RoutedEventArgs e)
{
dtg_MyDeskOrderGrid.SelectionChanged -= dtg_MyDeskOrderGrid_SelectionChanged;
}
However as this solution only disconnected the one event and didn't solve the root problem of old views lingering in the background and firing events before being cleaned up, I finally went the following code that keeps only one instance of my view in memory and reuses it.
private MyDeskView? currMyDeskView = null;
private void btn_MyDesk_Click(object sender, RoutedEventArgs e)
{
if (currMyDeskView == null)
{
currMyDeskView = new MyDeskView();
}
MainFrame.Navigate(currMyDeskView);
}
Thank you to everyone who helped me get over this bug.

C# Winform label disabled when switching to another form

I'm new to Visual Studio & C#, still trying to learn.
I have two forms Form 1 and 2
Click on a label in form 1 will go to form 2.
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
linkLabel1.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline;
(new Form2()).Show(); this.Hide();
}
However for form 2, the color of the label text changes to light grey text even though the ForeColor properties is black.
Am i missing out something here? Thank you.
Update: Seems like the text in form 2 appears but it is disabled (greyed out). Is there a way to enable the label? Not sure why is it even disabled in the first place.
Managed to resolve my issue.
Error msg: forms that are not enabled cannot be displayed as a modal dialog box
The form was not enabled, so i had to enable it
oneDriveForm.Enabled = true;
Full code below
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
linkLabel1.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline;
SubOneDriveForm oneDriveForm = new SubOneDriveForm();
oneDriveForm.Enabled = true;
oneDriveForm.ShowDialog();
}
Reference:
Button enabling not working correctly

UWP CustomRenderer for Checkbox: Pointer over Checkbox changes style?

I'm working with Xamarin.Forms and I made a CustomRenderer for Checkbox in UWP. When I set all the Checkboxes of my items in the ListView to true by clicking the button "Alle", the Checkboxes are displayed correctly with the check inside the box:
However, if I hover my mouse over the Checkboxes, they immediately change their appearence (the check disappears but it's still selected). In the following screenshot, I moved my cursor over the 3rd - 7th Checkboxes:
This is my overridden OnElementChanged method in the CustomRenderer:
protected override void OnElementChanged(ElementChangedEventArgs<EvaCheckbox> e)
{
base.OnElementChanged(e);
var model = e.NewElement;
if (model == null)
{
return;
}
nativeCheckbox = new CheckBox();
CheckboxPropertyChanged(model, null);
model.PropertyChanged += OnElementPropertyChanged;
nativeCheckbox.Checked += (object sender, Windows.UI.Xaml.RoutedEventArgs eargs) =>
{
model.IsChecked = (bool)nativeCheckbox.IsChecked;
};
nativeCheckbox.Unchecked += (object sender, Windows.UI.Xaml.RoutedEventArgs eargs) =>
{
model.IsChecked = (bool)nativeCheckbox.IsChecked;
};
SetNativeControl(nativeCheckbox);
}
I tried to override the PointerEntered event of nativeCheckbox. It works, for example if I set the model.IsChecked to true on this event, it will be set to true:
nativeCheckbox.PointerEntered += (s, args) =>
{
model.IsChecked = true;
};
But I don't know how to (if even at this place) prevent the checkbox from changing it's appearance when moving the cursor above the Checkbox. Just leaving the triggered event with empty code like this won't change anything about the described behaviour:
nativeCheckbox.PointerEntered += (s, args) => { };
How can I prevent the Checkbox from changing it's appearance when I move my cursor over it?
Update:
I've created a sample project for this issue. You can find the repository here: https://github.com/Zure1/CustomCheckbox
It has the exact same described behavior. In the following screenshot I pressed the button "All" on the bottom of the screen and then the checkboxes look like correct with a check inside of them:
After moving the mouse cursor over the bottom 3 checkboxes, their change their appearance:
Information: I'm debugging on my desktop (Windows 10). I don't know if this issue exists on WinPhone. Just in case you're wondering why my checkboxes are red: My system color in Windows is red.
This is a tricky one as I have been struggling with this issue for a while, I'll try my best to answer this.
TL;DR: It's caused by ViewCell.
The issue comes down to Xamarin Forms ListView and ViewCell.
I haven't been able to track down the cause yet for many months and the way I get around this issue is by refreshing the ListView every time a change happens forcing a redraw of the entire ListView which can really impact performance.
My educated guess on what the cause could be is the rendering code for the ViewCell is missing something.
As for your particular issue, I have created a CheckBoxCell which you can use to display a list of checkboxes with a title. I forked your project and made the changes.
This will display something similar to what you are trying to achieve and doesn't have rendering issues so will be a good starting point. You are able to customize this to display images and the like but you'll have to do that in the platform-specific layout code.
Please note that I have only created the code for UWP and that should be enough to get you going for the other platforms.
I hope this helps somewhat.

Value check when set not changed

Is there an event I can use for whenever the value of a NumericUpDown Control is set. Not just changed because alot of the times it is set programatically to the same value but the event still needs to be called.
Edit: I mean its not very complicated code its just there's alot of it. because this is pretty much the same for all the body parts
private void NumUpDownLeftHandDirection_ValueChanged(object sender, EventArgs e)
{
game.Ragdoll.LeftHand.DirectionOffset = (float)NumUpDownLeftHandDirection.Value;
game.Ragdoll.Direction = game.Ragdoll.Direction;
MainTimeLine.Frames[MainTimeLine.CurrentFrame].LeftHandDirection = (float)NumUpDownLeftHandDirection.Value;
}
I could just put it all in properties but that will be alot of work since I've already coded this expecting it to work.

Second TextBox showing same Text Selection as first

Long time listener, first time caller here. I'm having a strange issue with the TextBox in WinRT C#/XAML that I hope someone may be able to help me with.
Basically, I'm working on creating a Custom Control that essentially requires a second TextBox to be a copy of the first, including showing the same Text, and showing the same Selected Text. Obviously for the Text requirement I simply respond to the TextChanged event on the first TextBox and set the Text of the second TextBox to the Text from the first, which works great.
For the Selected Text requirement I started with a similar solution, and my code for this is as follows:
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
This seemed to work pretty well when initially used with a mouse:
But I'm having a problem when selecting text with Touch. I double-tap within the TextBox to create the first "anchor" as you do in Touch, then drag to begin the selection; but I only ever manage to select a single character normally before the selection stops. The TextBox doesn't lose focus exactly, but the behaviour is similar to that; the selection anchors disappear and I can't continue selecting anything unless I re-double-tap to start a new selection. If I remove the code to select text in TextBox2 then the Touch selection behaves perfectly in TextBox1.
I've been trying to fix this for a while and cannot, I'm not sure if I can get the desired behaviour with WinRT TextBoxes. Does anyone have any ideas? Or perhaps another way to implement a solution with two TextBoxes with this behaviour?
Thanks a lot.
So this is far from an answer, but discovered a few things that maybe will help you or others come up with a potential workaround. Apologies if these are things you've already seen and noted.
First, it's not the call to TextBox2.Select() that's the problem per se. This for instance, works fine for me
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(3, 5);
}
unfortunately, using start and length versus the hard-coded 3 and 5, that is, the following, DOES NOT WORK:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(start, length);
}
I also discovered that I could select TWO characters if I started from the end, but only one from the beginning. That got me to thinking about dispatching the call to set the second selection:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low,
() => TextBox2.Select(start, length));
}
Now I can select 2 from the front and 3 and sometimes 4 from the back. Took it a step further, and was able to select as many as six or seven with a really fast swipe.
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunIdleAsync((v) => Highlight());
}
public void Highlight()
{
TextBox2.Select(TextBox1.SelectionStart, TextBox1.SelectionLength);
}
Seems like the trick to working around this is not setting TextBox2 until whatever vestiges of the TextBox1 SelectionChanged event have completed.
This may be worth registering on Connect.
Mine is only a partial solution as well.
I did some debugging and noticed that the SelectionChanged event is fired throughout the text selection process. In other words, a single finger "swipe" will generate multiple SelectionChanged events.
As you found out, calling TextBox.Select during a text selection gesture affects the gesture itself. Windows seems to stop the gesture after the programmatic text selection.
My workaround is to delay as long as possible calling the TextBox.Select method. This does work well, except for one edge case. Where this method fails is in the following scenario:
The user begins a select gesture, say selecting x characters. The user, without taking their finger off the screen, pauses for a second or two. The user then attempts to select more characters.
My solution does not handle the last bit in the above paragraph. The touch selection after the pause does not actually select anything because my code will have called the TextBox.Select method.
Here is the actual code. As I mentioned above, there are multiple selection changed events fired during a single selection gesture. My code uses a timer along with a counter to only do the programmatic selection when there are no longer any pending touch generated selection changed events.
int _selectCounter = 0;
const int SELECT_TIMER_LENGTH = 500;
async private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
// _selectCounter is the number of selection changed events that have fired.
// If you are really paranoid, you will want to make sure that if
// _selectCounter reaches MAX_INT, that you reset it to zero.
int mySelectCount = ++_selectCounter;
// start the timer and wait for it to finish
await Task.Delay(SELECT_TIMER_LENGTH);
// If equal (mySelectCount == _selectCounter),
// this means that NO select change events have fired
// during the delay call above. We only do the
// programmatic selection when this is the case.
// Feel free to adjust SELECT_TIMER_LENGTH to suit your needs.
if (mySelectCount == _selectCounter)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
}

Categories