WPF ListBox Scrolling and Button Visibility - wpf

I am replacing the scroll bar for a list view with a "scroll up" and "scroll down" buttons. My question is, is there any way to show the buttons only when the list box can be scrolled?
i.e. My listbox may only have a couple of items...in that case I wouldn't need to show the buttons becuase there is nothing to scroll to.
I'm implmenting this across multiple listboxes and there is no set size of the items/lisboxes. I'm hoping there is some event that I can hook onto like a "scrollviewer_initializeed" or something.

Set the ListBox.ScrollView.VerticalScrollBarVisibility to Hidden and handle the ListBox.ScrollView.ScrollChanged event like this:
<ListBox ScrollViewer.ScrollChanged="ListBox_ScrollChanged"
ScrollViewer.VerticalScrollBarVisibility="Hidden" />
And then add this method to handle the ScrollChanged event:
private void ListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ButtonScrollUp.Visibility = ButtonScrollDown.Visibility =
((ScrollViewer)e.OriginalSource).ScrollableHeight > 0
? Visibility.Visible
: Visibility.Collapsed;
}
This is assuming your buttons are named ButtonScrollUp and ButtonScrollDown.
ScrollViewer.ScrollableHeight will equal the number of items out of view, so if it is greater than 0 your buttons should be visible.

The simplest solution would be to custom style the scrollviewer:
Simply set the Vertical scroll bar's visibility to "Auto", and hide all parts of the control template except for the top and bottom "RepeatButton" parts.
An example of styling the scrollViewer is here, but I'm sure you could find better ones with a quick search.

Related

How to use the context menu of the parent in a textbox

I have a listbox with several controls. Each control contains an custom autocompletebox which contains a System.Windows.Controls.AutoCompleteBox. When I right click on the control a custom contextm menu shows up. But with a right click on the textbox there appears the default contextmenu of the TextBox (with Copy, Cut and Paste).
My goal is to show my custom context menu with a right click on the TextBox.
Further informations:
My custom context menu is defined in the DataTemplate of the ListBox but I could define it in the Ressources or somewhere else as well.
I tried:
- when I null the context menu of the custom autocompletebox or the System.Windows.Controls.AutoCompleteBox of it, there is no effect at all
Thanks for every help ;)
You can either bind the context menu property to parent element's context menu or bind to the context menu once you define in the resource.xaml
Try using PreviewMouseDown instead of MouseDown to handle the MouseDown event.
In XAML:
<ListBox Margin="3" PreviewMouseDown="MouseDownOnListBox">
In Code:
private void MouseDownOnListBox(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
{
//Display your context menu
}
}
If you are using PreviewMouseDown on a list, when you click anywhere on the list, this event will be triggered first.

WPF DataGrid loses focus after row delete / cut

I have a DataGrid implemented in an MVVM/Prism application. The DataGrid supports Cut/Copy/Paste/Delete through a context menu and keyboard gestures.
I find that when a row is deleted/cut the entire DataGrid loses focus and keyboard focus moves to the last focused control.
Is there anyway to prevent this?
After removing a row I may want to re-paste into the DataGrid. Furthermore if the grid is empty there is no way at all for it to get keyboard focus. Clicking an empty grid does not give it focus.
Here is a similar question, but it doesn't solve the issue for me:
DataGrid Looses Focus When Delete Key is Pressed
You could set the DataGrids Focus in the PreviewKeyDown-Event
private void TheDataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
var grid = (DataGrid)sender;
FocusManager.SetFocusedElement(Window.GetWindow(grid), grid); //not tested
}
}
If you dont want to put code in code-behind use AttachedProperties in combination with the DependencyPropertyChanged-Event.
How to set set focus.
A dirty solution might be to handle the LostFocus event exposed by DataGrid and set focus on the control.
It arguably marginally infringes on the MVVM pattern i.e keeping the view dumb as hell, but it's still view code.

Prevent WPF ListBox from selecting item under mouse when layout changes

If a WPF ListBox gets a MouseMove event while the mouse button is held down, it will change the listbox's selection. That is, if you click the mouse on item #1, and then drag over item #2, it will deselect item #1 and select item #2 instead. How can I prevent this?
That's the short version. The slightly longer version is this: When the user double-clicks an item in my ListBox, I make other changes to my layout, which includes showing other controls above the ListBox. This moves the ListBox downwards, which means the mouse is now positioned over a different ListBoxItem than it was when the user double-clicked.
Since I make these layout changes in response to the DoubleClick event (which is a mouse-down event), it's very likely that the mouse button will still be pressed when this layout change completes, which means WPF will send the ListBox a MouseMove event (since the mouse's position, relative to the ListBox, has changed). ListBox treats this as a drag, and selects the event that's now under the mouse.
I don't want the selection to change between the time I get the double-click event and the time the user releases the mouse (which might be well after the layout changes). I suspect that the simplest way to achieve this would be to disable the "change selection on drag" behavior, but I'm open to other suggestions.
How can I "lock in" the selection on double-click, and prevent it from changing until mouseup?
After some digging around in ILSpy, I found that there's no property that disables the "drag to select" behavior, nor is there an event I can mark as Handled to stop it.
But there is a good inflection point for changing this behavior: ListBoxItem.OnMouseEnter is virtual, and it calls back into the listbox to change the selection. It doesn't seem to do anything else substantive, so all I need to do is override it and do nothing.
EDIT: As it turns out, the above only keeps the selection from changing while you move the mouse around inside the listbox. It doesn't help if you move the mouse above or below the listbox -- then the auto-scroll kicks in and moves the selection. Most of the auto-scroll code is again in non-virtual methods; it looks like the best way to prevent auto-scroll is probably to disable mouse capture. Another override on ListBoxItem can take care of this.
It looks like the best way to use my own ListBoxItem descendant is to descend from ListBox. The final code looks something like this:
public class ListBoxEx : ListBox
{
protected override DependencyObject GetContainerForItemOverride()
{
return new ListBoxExItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is ListBoxExItem;
}
}
public class ListBoxExItem : ListBoxItem
{
private Selector ParentSelector
{
get { return ItemsControl.ItemsControlFromItemContainer(this) as Selector; }
}
protected override void OnMouseEnter(MouseEventArgs e)
{
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
ParentSelector?.ReleaseMouseCapture();
}
}

Silverlight ScrollViewer takes focus when scrollbars are not visible

I'm finding that Silverlight's ScrollViewer will still take focus even when the scrollbars are not visible.
Has anyone else seen this issue? Are there any workarounds that will prevent the ScrollViewer acting as a tabstop when the scrollbars are invisible?
Thanks,
What about:
<ScrollViewer IsTabStop="False" ...
There is a simple solution, at least in Silverilght 4 and up. Listen to the LayoutUpdated event on the ScrollViewer and set the IsTabStop property based on the status of the scrollbars.
For example, if you only are using a vertical scroll bar:
void myScrollViewer_LayoutUpdated(object sender, EventArgs e)
{
//this should only be a tabstop if the scrollbar is visible.
myScrollViewer.IsTabStop =
(myScrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible);
}

Scrolling a listbox with page up/down

I had an ItemsControl, which you could use page up/down buttons to scroll expectedly. I switched it with a ListBox, to apply (thru triggers) a new DataTemplate when an item is selected.
Everything works fine, until using pageup or pagedown buttons. Instead of scrolling one page, it scrolls till the end or the beginning.
My previous attemps:
Not changing the item height when DataTemplate changes
Removed IsSelected=True trigger completely
All SelectionMode values
Do I miss something trivial?
private void RaiseKeyDownUpEventsOnEntitiesBox(Key key)
{
KeyEventArgs keyEventArgs = new KeyEventArgs(
InputManager.Current.PrimaryKeyboardDevice,
Keyboard.PrimaryDevice.ActiveSource,
System.Environment.ProcessorCount, key);
keyEventArgs.RoutedEvent = UIElement.KeyDownEvent;
entitiesBox.RaiseEvent(keyEventArgs);
keyEventArgs.RoutedEvent = UIElement.KeyUpEvent;
entitiesBox.RaiseEvent(keyEventArgs);
}
Page Down
RaiseKeyDownUpEventsOnEntitiesBox(Key.Next);
Page Up
RaiseKeyDownUpEventsOnEntitiesBox(Key.Prior);
Indeed, I missed something trivial. I forgot to remove the ScrollViewer outside the ItemsControl. I guess, this creates a confusion, since ListBox has its own ScrollViewer.
This raised another question. Previous ScrollViewer were automaticcally scrolled down from code behind. Now, that I can't reach the ListBox's ScrollViewer, I can't call its LineDown method. Here is my workaround:
// Responses is the ItemsSource
Responses.Add(e);
// xResponses is the ListBox
var item = xResponses.ItemContainerGenerator.ContainerFromIndex(0);
ScrollBar.LineDownCommand.Execute(null, item as IInputElement);
In the beginning, item might evaluate to null, however this does not create a problem. After adding a few items, luckily before we need to scroll, a container is returned successfully. Note that index is not important here, all we need is an IInputElement inside the ScrollViewer.

Resources