WPF TextBox with both static and editable text? - c#

I have a data entry application, with (among other things) a textbox for recording comments. These comments are specific to the data being entered, and often times are redundant (same comment given for a range of data records).
I'm planning to add a combobox with a canned selection of comments to cover the most common situations. When one is selected from the combobox, the comment textbox is populated with the canned comment.
However, I also need the ability to enter additional comments after the canned message, within the textbox. But I don't want it to be possible for the canned message to be altered. All entered comments need to come after the canned comment.
Is there a way to apply static text to a textbox which cannot be altered, but still allow text to be entered below it?
The only idea I've come up with so far is to catch TextInput events and continually overwrite the beginning of the textbox content with the canned message, but the result wouldn't exactly be pretty.

You could just place a disabled TextBox immediately above the editable TextBox and remove their bottom and top borders respectively so that they look like one big TextBox.

Perhaps overwrite a TextBox template so that it contains a Panel with the Canned Message ComboBox and a regular TextBox for user input.
Style the inner TextBox so it doesn't have the regular TextBox border, and style the ComboBox so that when it doesn't have focus it doesn't show it's border either.
When the ComboBox has focus, it will look like a ComboBox inside a TextBox, and if it doesn't have focus it will just look like one big TextBox

No, as much I aware of , you can not have something like this. But you can:
Have a label on top (side) of it with static text applied
If you have enough space, have a readonlt text box for preview of the comment, more or less like SO comment editor works.
You can try to not let to delete several count of characters from binded data ( which will be actually static text)
Hope this helps.

I would adopt a slightly different strategy.
If something has been selected in the Combobox, then concatenate the input in the selected combo-box item text and the textbox text. If not, use the textbox text.
Of course you could use the selected event of the combobox to chnage the label to reflect the change in circumstance.

I think you can bind the textBox1.Text with the combobox selected item as Oneway mode. The following is code snipet
<ComboBox Height="23" HorizontalAlignment="Left" Margin="118,48,0,0" Name="comboBox1" VerticalAlignment="Top" Width="144">
<ComboBoxItem Content="Commanet 1" />
<ComboBoxItem Content="Comment 2" />
</ComboBox>
<TextBox Height="64" HorizontalAlignment="Left" Margin="118,101,0,0" Name="textBox1" VerticalAlignment="Top" Width="144" Text="{Binding ElementName=comboBox1, Path=SelectedItem.Content, Mode=OneWay}" />

2 more options.
Override the style of the textbox to include the fixed text - pass the fixed text though some templatebinding
You can capture the PreviewKey<> events on the textbox and cancel it its modifying the "fixed" text, and if not let the event go through.
But 2 textboxes that visually look as 1 is still a better option though - easiest to implement and maintain

Related

Combine TextBoxes into one from an ItemsSource

Is there a way to combine all the textboxes that this itemscontrol creates so I can select them all as in a single textbox or textblock? As of right now, I can only select the text in a single textblock at a time.
<ItemsControl Background="WhiteSmoke" ItemsSource="{Binding SelectedItemNotes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBox IsReadOnly="True" Background="Transparent" BorderThickness="0">
<TextBox.Text>
<MultiBinding StringFormat="{}{0} {1} - {3}">
<Binding Path="Timestamp" />
<Binding Path="UserName" />
<Binding Path="Notes" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So as far as text selection interaction goes, you want the user to interact with the text in multiple text boxes it as if it were all in one big multi-line textbox: User clicks between the fourth and fifth characters in the first box, drags to just before the ninth character in the third box, and releases the left mouse button. The result is that everything after the fourth character in the first text box is selected, all of the second text box is selected, and the first eight characters of the third are selected.
There's nothing that'll do that for you. You'd be writing custom mouse interaction. I've done text selection with a mouse, though only in a single control, and it's finickier than you realize, but it's pretty awesome when it's finally working right.
So you'd set up some private state in your control class so the mouse events know that the user is engaged in this mega-selection interaction. Mousedown and drag in a textbox in the ItemsControl would launch that, mouseup in one would end it.
On mousemove, you'll have to set SelectionStart/SelectionEnd for each of the textboxes between the one you started at, and the one you're over. For the one you're over (if it's not the first one), you'll have to do custom code to find out which character the mouse is over, and programmatically set SelectionStart and SelectionEnd.
Don't forget that the user can drag-select "upward" from TextBox 2 to TextBox 0 you need to know which way the selection is going.
Once you know which textboxes are in your selection, write a property that enumerates those. Given that, once they have the appropriate text selected, it's easy to get the full selection text:
// In order of first in UI to last, regardless of "selection direction"
protected IEnumerable<TextBox> MegaSelectionTextBoxes {
get {
// Whatever -- might be a good idea to keep them
// in a List<TextBox> or ObservableCollection<TextBox>
}
}
// The easy part
public String MegaSelectionText {
get {
return
String.Join("\n",
MegaSelectionTextBoxes.Select(
tb=>tb.SelectedText));
}
}
Myself, I wouldn't count on getting that working really right in less than a week. Your definition of "right" may be a lot more permissive though.
But I would prefer an approach that works with XAML rather than trying to work around it.
If it were me, unless this feature was really critical for some reason (and sometimes they are), I'd make a case to sacrifice the partial selection in the first and last textboxes in the selection.
I'd look at using a multiselect ListBox rather than an ItemsControl, so I could let the user select items. Then I'd bind SelectedItems on the ListBox to an ObservableCollection on my viewmodel, and write a Command on my viewmodel that does whatever I want with the concatenated text of all the selected items.
Another option is use a DataGrid which multiple cell selection. That'll get you the interaction you want, though you may have to play some games to get it to look the way you want it to.

Change UI-layout based on selected ComboBoxItem

I have a ComboBox like this:
<ComboBox>
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem>ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
and I below that I have a grid, where the rest of the UI is. And I wanted to ask what the best way would be to display a other ui for each of the items.
Like for "Item #1" I'd like to have a radio button and a text field and for "Item #2" id like to display some data in a TextBlock, ... (Note: the ComboBox should stay at the same position to switch)
I'm not quiet sure how to implement this right with the MVVM-Model and I didn't find something useful for my problem in the internet so far.
I got it to work due to the help of HighCores comment.
I looked at this link about TabControl and transfered it to ComboBox.
So my XAML looks like this:
<ComboBox Name="RouteOptions"
ItemsSource="{Binding}"
DisplayMemberPath="DisplayName"/>
<ContentPresenter
Content="{Binding SelectedItem, ElementName=RouteOptions}"/>
And for the rest I just followed the instructions of the answer of the mentioned link.

wpf combobox default behaviour

I have a combobox in a wpf c# application.
What i am trying to do is the following.
I have a unselected combobox, as you look at it i can see an arrow to the right hand side and a space for text on the left. For the purpose of this question i'll refer to this text as 'Cell Text'.
When you select the button it appears with a list. I want this list to contain a number of robots my GUI/PC can connect to. When i select a robot, a message is sent to this robot trying to connect with it.
The 'Cell Text' i want to display the name of the currently connected Robot. There will be situations when a connection to a selected robot would'nt be possible, also a successful connection could take 5 seconds.
What i need to do is stop the selection automatically appearing in the 'Cell Text', is this possible?
Thanks
<ComboBox ItemsSource="{Binding MyRobotOptions}" Grid.Column="1" SelectedItem="{Binding SelectedRobot}" Margin="5"/>
For an inexperienced user (no offence), one of the easiest ways you can do this is to overlay a TextBlock over the 'Cell Text', as you call it:
<Grid>
<ComboBox ItemsSource="{Binding MyRobotOptions}" Grid.Column="1" SelectedItem="{
Binding SelectedRobot}" Margin="5" />
<TextBlock Text="{Binding YourSelectedRobotName}" Background="White"
Margin="0,0,24,0" />
</Grid>
I haven't been able to test this, so you might need to adjust the Margin property values to make it fit better, but it should hide the original text value.
A better solution I think is to use a separate indicator for connection state. For example a colored border around the Combobox that turns green when connected, red when disconnected. That way you don't have to break the paradigm of a ComboBox that everyone assumes: when you select something it immediately appears selected in the ComboBox.

Why does my comboBox not allow me to add values to it?

I have this WinRT XAML:
<ComboBox x:Name="comboxGroupName" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Margin="4" Width="200" Height="36" HorizontalAlignment="Left" ></ComboBox>
When I click in it to enter a new value, though, it seems to convert itself into a readonly textbox (it loses its down arrow and disallows any typing into it). What do I need to do to allow adding values into the comboBox? Or do I need to use a separate TextBox to do that (I reckon so, but I'd like to avoid that if reasonably possible)?
It looks like your only option will be to use a seperate TextBox. There is an IsEditable property, but it states:
Gets a value that indicates whether the user can edit text in the text box portion of the ComboBox. This property always returns false.
and the ComboBox Page states:
You populate the ComboBox by adding objects directly to the Items collection or by binding the ItemsSource property to a data source. Items added to the ComboBox are wrapped in ComboBoxItem containers.

wpf updating text block

I am trying to create some form of updating area in wpf. It needs to be up datable as it will be connected to a live stream of text that will constantly need to be displayed.
The idea is that I will have a stream of data which will comprise of a UserName and Text, this will come in a random times and need to be displayed:
User:Test :: Test:TextData
User:NextTest :: Test:TestData
and so on each item on a new line, so the object needs to be up datable in a scrolling format so the new item will be added to the bottom.
Currently I am using:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<TextBox Margin="5" TextWrapping="Wrap" AcceptsReturn="True" IsReadOnly="True" x:Name="LogDetails"></TextBox>
</StackPanel>
</ScrollViewer>
However this does not really show the data very well, the data is just string based, does anyone know of a better solution?
Thanks
The question is a little bit vague, but here a try:
As an option, why not using TextBlock instead of TextBox, if the text changes automatically?
Caveat: If you want to use the TextBox, don't forget to set the UndoLimit to 0 . Otherwise, you will have a lot of memory consumption, if you change the TextBox contents continously.
<TextBox UndoLimit="0" .../>
If your text is a concattenation of multiple string-elements, create a layout with a grid and use multiple TextBlocks to shown the data more nicely? Maybe there is also some data you can visualize as symbols?
If it is a log, maybe you want to fill a list with strings and set this list as the ItemsSource of an ItemsControl? Through the ItemTemplate-property you can then specify the layout of each item? Use an ObservableCollection<string>, then you only have to add the strings to the collection and the ItemsControl will refresh automatically. You can use ItemsControl, ListBox, ListView for such a log.

Categories

Resources