I created a simple AutoCompleteBox in my WPF app and it loads great with code intercepting the Populate event, but when the list pops up and I hit the arrow down key and get to the end of the list the vertical scroll bar doesn't scroll.
The values keep changing in the field like it is scrolling through them, but the scroll bar doesn't move.
If I use the mouse it scrolls fine.
I just need the arrow key to scroll it.
Any ideas/suggestions?
I am new to WPF and have searched forever for this fix.
Attach a SelectionChanged event and then, inside the handler:
private void AutoCompleteBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
AutoCompleteBox box = (AutoCompleteBox)sender;
ListBox innerListBox = (ListBox) box.Template.FindName("Selector", box);
innerListBox.ScrollIntoView(innerListBox.SelectedItem);
}
I see the same behavior. I found a post on codeplex talking about a different issue but at the bottom of the post they have a class AutoCompleteBoxEx that supports ScrollIntoView, so you can hook up the SelectionChanged even and this should get you the behavior you want. I have no idea why this is not baked in. I have had a chance to test out the posted code.
Update
Just pasted the code from the post into a class and used it in the XAML by changing AutoCompleteBox to AutoCompleteBoxEx and adding namespace for AutoCompleteBoxEx and it worked fine. You don't have to specify any event in the XAML, nor do you need to add any code to the code behind.
Related
In my application, I need to select the newly created document(note) when I go back to library. After library item is selected, the Library must be scrolled to the selected item.
My library's OnLoaded method:
private async void OnLoaded(object sender, RoutedEventArgs e)
{
await this.ViewModel.InitializeAsync();
// CollectionViewSource of my GridView being filled
ViewModel.CollectionChanging = true;
GroupInfoCVS.Source = ViewModel.GroupsCollection;
ViewModel.CollectionChanging = false;
// Loading Last selected item - THIS CHANGES SELECTION
ViewModel.LoadLastSelection();
}
After I call the LoadLastSelection method, selection is changed successfuly (I've tested). This is the method that is called after that (in our GridView's extended control):
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.SelectedItemsCount = this.SelectedItems.Count;
var newlySelectedItems = e.AddedItems;
if (newlySelectedItems.Any())
{
var item = newlySelectedItems.Last();
ScrollTo(item);
}
}
private void ScrollTo(object item)
{
UpdateLayout();
var itemUI = (FrameworkElement)this.ContainerFromItem(item);
if (itemUI != null)
{
_scrollViewer.UpdateLayout();
_scrollViewer.ChangeView(null, itemUI.ActualOffset.Y - itemUI.ActualHeight, null, false);
}
}
This also works for the most part. When itemUI is not null, the method scrolls successfully to the required item. The problems start when the items start to overflow the screen size. When items are completely hidden from the screen, they are virtualized. That means that ContainerFromItem returns null, so I can't take the offset properties. Keep in mind that this actually occurs before Library's OnLoaded method is finished.
Please, help me with some alternative to get such properties or other methods of scrolling, which will help me scroll successfully.
I've read a lot and tried using Dispatcher.RunAsync and ScrollIntoView methods, but I couldn't manage to produce any scrolling behavior. If you point me how to use them successfully, that would be a nice help too.
Here's what I've read (and tried):
ItemContainerGenerator.ContainerFromItem() returns null?
How to Know When a FrameworkElement Has Been Totally Rendered?
Is there a "All Children loaded" event in WPF
Let ListView scroll to selected item
Thanks in advance!
IMPORTANT: If you don't want to read all the conversation within the official answer, please read the solution in short here:
TemplatedControl's style had changed ScrollViewer's name from "ScrollViewer" to "LibraryScrollViewer" and that rendered ScrollIntoView method useless.
For GridView, the best way to achieve your needs is to call GridView.ScrollIntoView.
But you seem to have made similar attempts, and it does not to be successful, then the following points may help you:
1. Don't use GridView as a child element of ScrollViewer.
In your code, I see that you are calling the method of ScrollViewer.ChangeView to adjust the view scrolling, so it is speculated that you may put the GridView in the ScrollViewer, which is not recommended.
Because there is a ScrollViewer inside the GridView, and its ScrollIntoView method is to change the scroll area of the internal ScrollViewer. When there is a ScrollViewer outside, the ScrollViewer inside the GridView will lose the scrolling ability, thus making the ScrollIntoView method invalid.
2. Implement the Equals method of the data class.
If your data class is not a simple type (such as String, Int32, etc.), then implementing the Equals method of the data class will help the GridView to find the corresponding item.
Thanks.
I have written a custom OnScreen Keyboard as an UserControl to have a better control over what the user can type (Alphanumeric/Numpad/Navigation Keys - stuff like that) and to have a better control over the screen layout at design time.
The OSK works by manipulating the text- and selection-properties/functions of a textbox-control.
My main Problem is how to find the right TextBox to inject text into.
My first, naive approach was to register every TextBox I want to use with the OSK Control manually and use the GotFocus/LostFocus of those registered TextBoxes to determine the active control:
public void RegisterInput(TextBox text) {
if (!_listeners.ContainsKey(text)) {
_listeners.Add(text, modes);
text.GotFocus += Input_OnGotFocus;
text.LostFocus += Input_OnLostFocus;
}
}
private void Input_OnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
if (_focused == sender) {
_focused = null;
IsEnabled = false;
UpdateKeyboardMode(); // << Updates Keyboard layout (Alphanumerical vs Numpad) based on focused control
}
}
private void Input_OnGotFocus(object sender, RoutedEventArgs routedEventArgs) {
_focused = (TextBox) sender;
IsEnabled = true;
UpdateKeyboardMode();
Bindings.Update();
}
I work with Focus here, because I need to determine which kind of keyboard (full-size alphanumerical vs. short numpad) to display for each TextBox. The _focused TextBox is then used to directly inject the pressed keys into it. In the constructor of my Page which also contains the OSK-control I would call RegisterInput() with a reference of each and every TextBox I defined on the page. This works just fine — if I have those references.
But now I am working with UserControls. That also removes the TextBoxes out of reach for direct referencing, but I could write some kind of VisualTree-Scan after InitializeComponent() to find all references and call RegisterInput() on each reference I found. If I only need to do this once, it isn't a problem (altough it is still ugly).
One step further - ListBoxes with dynamicly changing contents and DataTemplates. Now I'd need to rescan the whole VisualTree explicitly everytime something changes. But how to detect those changes?
The question is: Can I get an event as soon as $any element in my VisualTree gets/looses focus, without knowing all those elements beforehand (thus replacing RegisterInput() completely)? Or can I listen to changes to the VisualTree to rescan all controls and then call RegisterInput() manually for every TextBox I found?
The goal is to get a handler called everytime a GetFocus/LostFocus event on any TextBox/Control in the UI is raised so that I can update the keyboard to either display a full-sized alphanumerical keyboard (for default textboxes) or a shortened numpad (e.g. for textboxes bound to numerical backing fields).
Alternatively: Is there any other way to inject text and call UpdateKeyboardMode() to update the keyboard layout as soon as the selected textbox changes?
Other options I thought about include:
Build a custom control which derives from a TextBox and let it register itself to the OSK. I'll probably resort to this method, if I don't find any better way. But this will destroy support for 3rd party libraries in which my control is not present and thus does not use the "special magical textbox with osk support".
Don't use events at all. Get the currently focused TextBox with the FocusManager as soon as the user presses a key on my OSK and inject text into the focused instance. Problem with this approach is, that it completely destroys the capability to adapt the OSK to different input types (alphanumerical vs only Numpad), because I cannot determine the keyboard type I need before pressing a key.
Rescan the VisualTree with a timer. Won't do that, thats simply too much of a hack.
Use the OnScreen-Keyboard supplied by Win10 IoT. Two problems: It has no designtime support and is displayed above elements, even if the focused element is directly underneath the keyboard (acceptable if neccessary), but I don't know of a way to change the keyboard "layout" between a full-sized alphanumeric keyboard and a shortened Numpad which only contains numbers and some keys. Also it does not allow to use custom keys (e.g. arrow keys for navigation, custom return key handling).
After a discussion in the chat forum, the actual problem isn't to create a Custom OSK control and use that to interact with the TextBoxs but instead, it's "being bound to use custom control" wrapping a textbox everywhere a OSK needs to be shown.
The Solution would be to listen to the OS-OSK events and when they are triggered, pop up the Custom OSK this ways you won't have to wrap a Textbox in a user control and use that throughout your project.
Link to the Documentation: - respond to the presence of the touch keyboard
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.
I have GridControl (DevExpress) of form. I want to call some method when position of vertical scrollbar in the end. Is this possible? Thanks.
EDIT
My solution(not exactly solve the question, but work great for me):
void gvDisplay_TopRowChanged(object sender, EventArgs e)
{
if (gvDisplay.IsRowVisible(gvDisplay.RowCount - 1) == RowVisibleState.Visible)
{
_lastFocusedRowHandle = gvDisplay.RowCount;
LoadNextPortionOfData();
}
}
I haven't used devexpress before but the way in going about handling this should still be the same or similar regardless as you will still need to create your own extended event. The following is what would be done for the default windows forms, if devexpress extends on this then there should be no problem.
Handling this would be done by an event being triggered. The component class you are using should have a Scroll event, this event is called when the position of the scroll bar changes. If you create a new component class and have it inherit from the component class you want you can then add features that you want. In this new component class you need to extend the event Scroll to check the Value property of the scrollbar. When using this new component class it will still have all the functionality that the original had but now with the new features you added.
For more reading:
Scrollbar class
http://msdn.microsoft.com/en-us/library/t2htecew.aspx
Scrollbar Scroll event
http://msdn.microsoft.com/en-us/library/system.windows.forms.scrollbar.scroll.aspx
I'm pretty new to C#/WPF, coming from Obj-c background. I'm not really sure how this works in terms of object oriented design, and how different classes see each other.
So I have a large view (MainView) that has some custom plots and a datagrid on the bottom (Datagrid is in its separate xaml and has .cs file behind it). There is a custom object that gets added to the plots that when you drag it, the datagrid gets updated (by using dataGrid.ScrollIntoView). The code for the ScrollIntoView is in the xaml.cs file of the Datagrid.
To me this makes sense since the MainView has all the components and "sees" all the objects, so when the event handler of the dragWindow gets called, then the MainView asks for the DataGrid, and calls its method to update its column position. (This is the way I understand it, please feel free to correct me if I'm wrong).
Now I want to go the other way as well. So that if I update the scrollbar horizontally, then the dragwindow in the MainView will get updated. This does not make as much sense to me. I can create an event handler in the xaml.cs of the datagrid. But it does not see the dragWindow in the MainView right? So I'm not quite sure how to start implementing this functionality. Any help is always appreciated. Thanks!
Your grid control should expose an event to notify any consumers (MainView in this case) that scrolling has taken place.
public class YourGridControl
{
public event EventHandler GridScrolled;
}
MainView can then attach a handler to this event in the designer or in the code:
gridCtrl.GridScrolled += OnGridScrolled;
private void OnGridScrolled(object sender, EventArgs e)
{
// Logic here
}