WPF ComboBox using shortcut keys for selecting items - wpf

I have a combo box in WPF that uses the following data template. With help from the forum I was able to get this to display and behave properly.
When the drop down is open I would like the user to be able to type a letter and have the drop down skip to that selection. I have seen this implemented two ways, one where it bascially captures the keyboard input in a text box in the combo box and selects based on what the user has typed. This allows the user to wait and type more text that gets add to the criteria. The other is where the keyboard input doesn't appear to get captured anywhere, if yo type a letter, wait a couple seconds and type another letter it takes you to the selection starting with the second letter you typed. If you want to type multiple letters of the search criteria you have to type them quickly together.
I'd be happy with either approach. They can only select an item though that is in the list, so I don't really like the idea of putting an edit control on the combo box where they can type in whatever they want. I could do this and than validate their input, but would rather force them to select something that is in the list.
In this case it is a list of system colors, which is over 140 of them, so having a way to quickly get around the list is what I need.
Here is my data template that I am using.
<DataTemplate x:Key="ColorSelectionComboBox" DataType="ComboBox">
<StackPanel Orientation="Horizontal">
<Rectangle Width="16" Height="16" Margin="0,2,4,2">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding Color}"/>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
Any ideas are appreciated.

ComboBox has built-in support for incremental search using the keyboard. I haven't actually used it (so I'm no good for help with advanced troubleshooting) but I know it's there.
It looks like you need to set the ComboBox's IsTextSearchEnabled property to true, and then set the TextSearch.TextPath attached property to the binding path of the text you want to search on (probably "Name" to correspond with your TextBlock text).

Related

Getting selected text from a RichTextBox only on MouseUp?

I'm a newbe to RichTextBox and unable to find the answer. In a RichTextBox (WPF) that is already holding text content, I would like to be able to place the cursor down on one letter; move the cursor horizontally while holding it down; then lift the cursor up. This results in the text being highlighted and selected. So far so good.
However, in the following XAML, the selection event is triggered for every character. I only want one firing for when the mouse is lifted off the box and ultimately would like to know the starting and ending insertion points for the selected text as well as the selected text. (I know this is simple, but I can't get it :( ).
XAML
<SimpleRichTextBox Name="simplerichtextbox" Grid.Column="1"
RichText="{Binding RichText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
SelectionChanged="simplerichtextbox_SelectionChanged"
>
<FlowDocument PageWidth="{Binding ElementName=simplerichtextbox, Path=ActualWidth}" />
<SimpleRichTextBox>
Any help is much appreciated.

Multiline for WPF TextBox

I am developing an app for sending some feedback.
Basically I'm trying to make a TextBox for comments, but I'm used to the WinForms MultiLine=true. I've set MinLines to 3, which is getting there, but preferably I'd like it if the user is able to type wherever in this block - like press enter and do dot points sort of thing. For example:
- Item 1 blah
- Item 2 blahlb lahbvl d
But at the moment the text all stays on one line.
- Item 1 blah - Item 2 blahb blahb blah
These comments will then help fill the body of an email which is sent. It may be pointless if I can't easily keep the same formatting when putting this string into the email body string (so that it looks like it does when sent as it does when typed).
Can I achieve what I'm after or do I have to leave it as all text on one line?
Enable TextWrapping="Wrap" and AcceptsReturn="True" on your TextBox.
You might also wish to enable AcceptsTab and SpellCheck.IsEnabled too.
Also, if, like me, you add controls directly in XAML (not using the editor), you might get frustrated that it won't stretch to the available height, even after setting those two properties.
To make the TextBox stretch, set the Height="Auto".
UPDATE:
In retrospect, I think this must have been necessary thanks to a default style for TextBoxes specifying the height to some standard for the application somewhere in the App resources. It may be worthwhile checking this if this helped you.
Here is a sample XAML that will allow TextBox to accept multiline text and it uses its own scrollbars:
<TextBox
Height="200"
Width="500"
TextWrapping="Wrap"
AcceptsReturn="True"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"/>
The only property corresponding in WPF to the
Winforms property: TextBox.Multiline = true
is the WPF property:
TextBox.AcceptsReturn = true
or
<TextBox AcceptsReturn="True" ...... />
All other settings, such as VerticalAlignement, WordWrap etc., only control how the TextBox interacts in the UI but do not affect the Multiline behaviour.
Contrary to #Andre Luus, setting Height="Auto" will not make the TextBox stretch. The solution I found was to set VerticalAlignment="Stretch"

WPF: Use SpellCheck On Read-Only TextBox

I'm looking to display text with the wavey red lines where a word is misspelt, but I only want the text to be selectable, not editable. If I set the TextBox's IsReadOnly property to True or IsEnabled to False, the wavey red lines disappear and I can't get around it by putting something transparent as this will prevent the user being able to select sections of the text.
Is there anyway I can keep the red lines, allow the text to be selectable but prevent the actual text being modified?
Thanks
You could hook up to on the text change event of the text box, and just reject the new text. It would have the same effect of readonly without graying out the textbox or getting rid of the spell checking.
Thanks David. I'm currently looking at 2 possible solutions, yours and the following:
I've created a custom control which is based on the standard TextBox, but effectively has 2 textboxes laid on top of one another in this manor:
<TextBox Name="tbxBack"
Foreground="Transparent"
SpellCheck.IsEnabled="True"
TextWrapping="Wrap"
SnapsToDevicePixels="True"/>
<TextBox Name="tbxFront"
Background="Transparent"
TextWrapping="Wrap"
SnapsToDevicePixels="True"
IsReadOnly="True"/>
I think it's pretty straight forward what's going on here, but I'm concerned about the potential overhead this will cause.
The reason I'm looking into the double TextBox solution is that I'm worried if I try and cancel the event, it could end up with some sort of flashing in the control when the text is changed.

Moving Keyboard Focus Away from ListBox

I'm developing a program in WPF (VB) that relies on keyboard navigation only.
In my program, I have a listbox that displays up to 20000 items.
What I want is that when the listbox has keyboard focus, and I move to the bottom item that is visible (using ArrowDown), I want the focus to move to the next item outside the listbox. I'm using PgUp and PgDown to scroll the listbox contents, and text search to jump to items.
Is there a way to detect if the focused/selected item is the last/first visible item in the listbox?
If so, I could just use:
ListBox1.MoveFocus(New TraversalRequest(FocusNavigationDirection.Down))
I'd suggest that you don't do this, the user interface should behave consitesntly with other user interfaces in the operating system.
Your users would be better off if you come up with an alternate user interface that's consistent with how user interfaces behave on your target operating system.
It is a little clear from your explanation but either your looking for:
navigation to move outside of the listbox when the last item is selected.
when navigation is attempted beyond the last item in the list that the navigation pops out of the listbox.
If (1) is your objective there is probably a reasonable solution using triggers and or some custom code handling for events based on the selected item and selected item changed. I would have to agree with Tom if this is the case though and suggest that you do not implement it this way since the last item will never be selectable without focus being programatically removed.
If your instead looking to do (2) then it is my experience that the natural behavior of a ListBox is to move to the next control when the Tab key is pressed and I've tested this for the down arrow key as well and it works the same. When I get to the last item in the list focus pops out of the listbox and to the next control according to it's parent.
UPDATE: I have to withdraw my original comments as the behavior I described above do not describe the default behavior in WPF for a ListBox however it is the behavior you will see the behavior I described above (which I believe is the behavior your looking for) when implementing an ItemsControl and specifying an ItemTemplate. Take a look at the following example.
<ItemsControl ItemsSource="{Binding ElementName=TheWindow, Path=ListOStrings}">
<ItemsControl.Template>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderBrush="Magenta"
BorderThickness="1">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
By chance, this just happens to have the behavior you described since each item in the list behaves almost like a control placed directly as a peer to all the other controls.
I use an easy trick to move the focus outside Listbox:
I disable the listbox so the focus moves automatically to the next control, then i enable the listbox again :)
Lst.IsEnabled = False
Lst.MoveFocus(New TraversalRequest(FocusNavigationDirection.Next))
Lst.IsEnabled = True

Display images in TextBlock (WPF)

I'm working on a simple chat application. Currently the messages are binded to a custom-styled listbox like this (simplified XAML):
<ListBox ItemsSource="{Binding MessageCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now I would like to be able to put images (like graphical smileys) into the displayed message text. Is there any way to achieve this using TextBlock (or any other standart component) or do I need to use some special control for this?
Thanks in advance
Just use the InlineUIContainer.
<TextBlock TextWrapping="Wrap">
<Run>Some text.</Run>
<InlineUIContainer>
<Image Source="http://sstatic.net/stackoverflow/img/apple-touch-icon.png" Height="20"></Image>
</InlineUIContainer>
<Run>Some more text.</Run>
</TextBlock>
The Content of a TextBlock is always just a series of Inlines, so you should use the InlineUIContainer. You can insert this container as one of the Inlines in your TextBlock wherever you want an Image to appear, alternating with text Runs. You could parse a message and at the same time keep adding the tokens (either text or images) that you find to the Inlines collection of the TextBlock.
If you want the Images actually inside the text (like an emoticon), then you are going to have to do some work. This sounds like one of the few times I would actually want a User Control, the point of which would be one that scans the Text looking for emoticon values and building a Data Template on the fly.
Remember that anything you can do in XAML you can do in code, so the code I'm thinking of would follow this general idea:
Scan text for emoticon values and
create a list of values for data
elements.
Create a DockPanel.
Foreach element in the List, add
either a TextBlock or an Image
(based on value).
Set this.Content to the DockPanel.
I think something like this is actually what you are looking for, but if you want just an Image, then the ValueConverter suggestion would work.
You could use a value converter to convert the text to another type which has a list of segments which are composed of either text or the smiley face (in the order in which they appear).
Then, you can use a data template to bind to that new type and display the text and smiley faces appropriately.
I also encountered this problem recently and I overcome this by
Creating an ListBox ItemTemplate containing an ItemsControl that has a WrapPanel in the ItemsPanelTemplate and then binding my string to the ItemsSource of the ItemsControl with a IValueConverter that houses all the logic.
Split out your words and query/search your emoticons strings, hyperlinks etc and create your TextBlock, Image, Hyperlink, Button elements and set your values and event handles.
In the function create a List<UIElement> and populate the List with the controls you have generated and return the List as the object in the Convert function of the IValueConverter.
Because you have the WrapPanel in there you get your wrapping done.
Use the Image element instead of the TextBlock and use a Converter to map the text value to the smile image.
<ListBox ItemsSource="{Binding MessageCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Text, Converter={StaticResource MyImageConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>

Resources