How to paste value when copying formatted text in TextBox - xaml

I have a TextBox in a Windows 10 UWP Application that looks like this.
<TextBox Name="QuoteBox"
MinHeight="160"
TextAlignment="Left"
TextWrapping="Wrap"
Margin="12"
RelativePanel.AlignTopWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignLeftWithPanel="True"
IsTabStop="True" KeyDown="InputBox_KeyDown"
Height="{x:Bind MainScrollViewer.ViewportHeight, Converter={StaticResource TwoFifthsConverter}, Mode=OneWay}" />
What I'm trying to do is copy / paste some text in this TextBox. The issue is that when I copy text from an e-mail, website or even OneNote, the text isn't pasted.
But when I paste that text in Notepad, and copy it from there to the TextBox, it works.
I assume this is because the text contains formatting and TextBox doesn't support pasting formatting text.
There were many questions like this, but they were concerning very specific solutions and custom Paste event handlers.
How can you paste text from within formatted text in a TextBox? Does it need a custom Paste event handler?
Thank you very much.

So I created an event handler for the Paste event. Basically what I did was just copy the text from the clipboard to the textbox Text property.
It is a simplification of the example found in the Paste event handler documentation page
/// <summary>
/// Used to paste text when copying formatted text
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void QuoteBox_Paste(object sender, TextControlPasteEventArgs e)
{
TextBox quoteBox = sender as TextBox;
if (quoteBox != null)
{
// Mark the event as handled first. Otherwise, the
// default paste action will happen, then the custom paste
// action, and the user will see the text box content change.
e.Handled = true;
// Get content from the clipboard.
DataPackageView dataPackageView = Clipboard.GetContent();
if(dataPackageView.Contains(StandardDataFormats.Text))
{
try
{
// Copy text from the clipboard
quoteBox.Text = await dataPackageView.GetTextAsync();
}
catch
{
// Ignore exception
}
}
}
}

Related

UWP - Print multiple xaml sheets using a single print command

Is there a way to accomplish the above.
There is a PrintHelper object in Windows Community Toolkit, you only have to instantiate the PrintHelper object and call AddFrameworkElementToPrint method to add the mutiple XAML controls you want to print.
In addition, when you initialize the object, you need to pass a XAML panel that will be used to host printable control. It needs to be in your visual tree but can be hidden with Opacity = 0, like below. For more details, you can refer to this document.
MainPage.xaml:
<StackPanel>
<Canvas x:Name="PrintCanvas" Opacity="0"/>
<Button Click="Button_Click">click</Button>
</StackPanel>
.cs:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var printHelper = new PrintHelper(PrintCanvas);
printHelper.AddFrameworkElementToPrint(new BlankPage1());
printHelper.AddFrameworkElementToPrint(new BlankPage2());
await printHelper.ShowPrintUIAsync("Title");
}

if text box First word "/" and Item description then form "itemsearch"

If textbox first word "/" and Item description then form "itemsearch" show and "itemsearch" textbox itemname = without "/" text that enter in last form
For Example:
/what is item
in Itemsearch form textbox.text = "what is item"
Add an event handler for LostFocus of the TextBox
XAML
<TextBox x:Name="tBox" LostFocus="tBox_LostFocus" ...
and handle it in your code behind file
private void tBox_LostFocus(object sender, RoutedEventArgs e)
{
tBox.Text = tBox.Text.Trim('/');
}
Anyway, if you want to implement a VIM-like search (looks sort of to me) you should save your search term without the / to a separate string. Users might find it confusing when the content of a recently filled out text box changes automatically

Binding to xaml page's DataContext in Windows Universal App

I'm using a content dialog do display instance data when an item in a grid is selected.
In the calling page's view model, when an item is selected the following method is executed.
public virtual void ItemSelected(object sender, object parameter)
{
var arg = parameter as Windows.UI.Xaml.Controls.ItemClickEventArgs;
var clickedItem = arg.ClickedItem;
var item = clickedItem as ItemsModel;
var dialog = new ItemsDialog();
dialog.DataContext = item;
dialog.ShowAsync();
}
This shows the dialog, and the content is displayed as expected. Now I'm trying to split my xaml into different templates and I'm trying to use a ContentControl to display the appropriate template. I've written a DataTemplateSelector to help choose the correct template, but now I cannot figure out the data binding for the ContentControl (see simplified version below).
<ContentDialog.Resources>
<UI:MyTemplateSelector x:Key="MyTemplateSelector"
Template1="{StaticResource Template1}"
Template2="{StaticResource Template2}"/>
<DataTemplate x:Key="Template1"/>
<DataTemplate x:Key="Template2"/>
</ContentDialog.Resources>
<StackPanel>
<ContentControl DataContext="{Binding}"
ContentTemplateSelector="{StaticResource MyTemplateSelector}"/>
</StackPanel>
When debugging into my ContentTemplateSelector, my binding is always null. I've tried various forms of the binding syntax with no luck. How do I properly set the DataContext of the ContentControl to that of the ContentDialog?
When debugging into my ContentTemplateSelector, my binding is always
null
You need to set data binding for the Content property of ContentControl control, see Remarks in MSDN:
The Content property of a ContentControl can be any type of object,
such as a string, a UIElement, or a DateTime. By default, when the
Content property is set to a UIElement, the UIElement is displayed in
the ContentControl. When Content is set to another type of object, a
string representation of the object is displayed in the
ContentControl.
So the following xaml should work:
<StackPanel>
<ContentControl Content="{Binding}"
ContentTemplateSelector="{StaticResource MyTemplateSelector}"/>
</StackPanel>
Check my completed sample in Github
You have to bind Content also.
Content="{Binding}"
You have the data source (DataContext) and how the data is displayed (templates) and now you need to specify which of the properties brings that together.

Silverlight 4 AutoCompleteBox, setting SelectedItem to null

In the source code of AutoCompleteBox (downloadable from Microsoft) I found the following:
/// <summary>
/// Called when the selected item is changed, updates the text value
/// that is displayed in the text box part.
/// </summary>
/// <param name="newItem">The new item.</param>
private void OnSelectedItemChanged(object newItem)
{
string text;
if (newItem == null)
{
text = SearchText;
}
else
{
text = FormatValue(newItem, true);
}
// Update the Text property and the TextBox values
UpdateTextValue(text);
// Move the caret to the end of the text box
if (TextBox != null && Text != null)
{
TextBox.SelectionStart = Text.Length;
}
}
What troubles me is {text = SearchText;} line. If I bind SelectedItem to my ViewModel and after a search entry into the AutoCompleteBox, SearchText is not empty, then when underlying data is reset to null, AutoCompleteBox may display SearchText instead of empty string. Can someone explain why it is written this way, and suggest a workaround?
I believe that's so that when there is no actual search item, the box displays something like "Search Here". For an example, see StackOverflow's search box, which says "search" when it is empty.
This is really annoying and I've yet to find a fix. It is on the Silverlight Toolkit issue tracker here. I've also read something here about setting the ItemsSource to null that I'm going to play about with.
I'll update if I find a workaround.

RichTextBox - retain original formatting (font), even after paste

I need to use a RichTextBox, not a normal textbox because of the way it keeps the caret position, from line to line. But I need to keep the text in the same font all the time even if it is pasted.
At the moment I have it selecting the entire text and changing the font to the original (Lucida Console) but it look horrible when you paste into it as it flashes blue.
If you are handling the pasting programatically don't use the Paste method. Instead use Clipboard.GetDataObject().GetData(DataFormats.Text) to get the text in a string and then add the text using the Rtf or Text property to the RichTextBox:
string s = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
richTextBox.Text += s;
Otherwise you could handle the Ctrl+V key press:
void RichTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if(e.Control == true && e.KeyCode == Keys.V)
{
string s = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
richTextBox.Text += s;
e.Handled = true; // disable Ctrl+V
}
}
Darin's method ignores caret position and always appends to the end of text.
Actually, there are better method. Use overload of RichTextBox.Paste():
DataFormats.Format plaintext_format = DataFormats.GetFormat(DataFormats.Text);
this.Paste(plaintext_format);
Works like charm for me.
Both #Darin & #idn's answers are good, however I could get neither to work when pasting the following rich text:
 This is text after an arrow.
This is a new line
The font would always change to WingDings. I had copied this from MS Word:
Specifically, the plain-text format method described by #idn above did indeed just paste plain text, but something was happening in which the font was changed too.
The following code handles the KeyUp event to just select all text and replace its original colours and font (i.e. formatting). To ensure that this isn't visible on the screen as a flicker, a special method of disabling window repaint events was employed. Control draw disablement occurs in the KeyDown event, the RichTextBox control handles the paste event by itself, and then Control drawing is re-enabled at the end. Finally, this only happens for CTL+V and SHIFT+INS, both of which are standard paste commands:
/// <summary>
/// An application sends the WM_SETREDRAW message to a window to allow changes in that
/// window to be redrawn or to prevent changes in that window from being redrawn.
/// </summary>
private const int WM_SETREDRAW = 11;
private void txtRichTextBox_KeyDown(object sender, KeyEventArgs e)
{
// For supported Paste key shortcut combinations, suspend painting
// of control in preparation for RTF formatting updates on KeyUp
if ((e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.V) || // CTL+V
(!e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Insert)) // SHIFT+INS
{
// Send Suspend Redraw message to avoid flicker. Drawing is
// restored in txtRichTextBox_KeyUp event handler
// [this.SuspendLayout() doesn't work properly]
Message msgSuspendUpdate = Message.Create(
txtRichTextBox.Handle, WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
NativeWindow window = NativeWindow.FromHandle(txtRichTextBox.Handle);
window.DefWndProc(ref msgSuspendUpdate);
}
}
private void txtRichTextBox_KeyUp(object sender, KeyEventArgs e)
{
// Following supported Paste key shortcut combinations, restore
// original formatting, then resume painting of control.
if ((e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.V) || // CTL+V
(!e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Insert)) // SHIFT+INS
{
// Layout already suspended during KeyDown event
// Capture cursor position. Cursor will later be placed
// after inserted text
int selStart = txtRichTextBox.SelectionStart;
int selLen = txtRichTextBox.SelectionLength;
// Replace all text with original font & colours
txtRichTextBox.SelectAll();
txtRichTextBox.SelectionFont = txtRichTextBox.Font;
txtRichTextBox.SelectionColor = txtRichTextBox.ForeColor;
txtRichTextBox.SelectionBackColor = txtRichTextBox.BackColor;
// Restore original selection
txtRichTextBox.SelectionStart = selStart;
txtRichTextBox.SelectionLength = selLen;
txtRichTextBox.ScrollToCaret();
// Resume painting of control
IntPtr wparam = new IntPtr(1); // Create a C "true" boolean as an IntPtr
Message msgResumeUpdate = Message.Create(
txtRichTextBox.Handle, WM_SETREDRAW, wparam, IntPtr.Zero);
NativeWindow window = NativeWindow.FromHandle(txtRichTextBox.Handle);
window.DefWndProc(ref msgResumeUpdate);
txtRichTextBox.Invalidate();
txtRichTextBox.Refresh();
}
}
A caveat of this approach is that, because the events are not suppressed (e.Handled = true;), the standard CTL+Z (undo) operation is supported. However this process cycles through undoing the format changes too. I don't see this as a big problem, because the next time that text is pasted, formatting is once again removed.
This approach isn't perfect, because if the text is copied and pasted from the RichTextBox (into another application), the newly applied formatting remains, but in my opinion, that's better than losing the undo functionality. If the undo functionality isn't important, then replace the text selection and formatting application with a replacement of the text to remove all formatting, as per this answer: https://stackoverflow.com/a/1557270/3063884
var t = txtRichTextBox.Text;
txtRichTextBox.Text = t;