I am using a RadGridView to display some string data in a column. I am using databinding. Some of my text strings have portions of the text encased with {} and I would like to display this text in a different color.
From looking around on the net I have found that I can change text color of text in a text block but Im having trouble applying this to a databound datagrid column.
Could anyone advise if this is possible.
---EDIT---
Heres xaml where I define datacolumn:
<telerik:GridViewDataColumn x:Name="colMasterValue" Header="Localise - Master Value" DataMemberBinding="{Binding MasterValue}" ShowDistinctFilters="False" IsReadOnly="True"/>
Heres the display:
So what I want is {Customer.Panel.field} to appear in a different color.
Let's try the next solution.
Will use a custom TextBlock that can separate regular character and the '{' or '}'.
Let's add the replace mechanism that can replace the original text with decorated text. Where all text except the '{' or '}' colored in some way.
Here is the xaml code:
<telerik:GridViewDataColumn DataMemberBinding="{Binding Path=Text}"
Header="HeaderName"
IsFilterable="False" IsReorderable="False">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate DataType="flowConfiguration:SomeDataType">
<modules:MyTextBlock Text="{Binding Text,
UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
Here is the MyTextBlock code
public class MyTextBlock:TextBlock
{
private DependencyPropertyDescriptor _descriptor;
private bool _isUpdating;
public MyTextBlock()
{
this.Unloaded += OnUnloaded;
_descriptor = DependencyPropertyDescriptor.FromProperty(TextProperty, typeof(TextBlock));
_descriptor.AddValueChanged(this, OnValueChanged);
}
private void OnValueChanged(object sender, EventArgs eventArgs)
{
if(_isUpdating) return;
_isUpdating = true;
var text = Text;
if(string.IsNullOrEmpty(text)) return;
Inlines.Clear();
UpdateInlines(text);
_isUpdating = false;
}
private void UpdateInlines(string text)
{
//text = #"{Customer.Panel.field}";
var runs = new List<Run>();
var sb = new StringBuilder();
foreach (var current in text)
{
if (current.Equals('}') || current.Equals('{'))
{
if (sb.Length == 0)
{
runs.Add(new Run
{
Text = current.ToString()
});
}
else
{
runs.Add(new Run
{
Text = sb.ToString(),
Foreground = Brushes.Red
});
runs.Add(new Run
{
Text = current.ToString()
});
sb.Clear();
}
}
else
{
sb.Append(current);
}
}
if(sb.Length > 0)
runs.Add(new Run{Text = sb.ToString(), Foreground = Brushes.Red});
runs.ForEach(run =>
Inlines.Add(run));
}
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
this.Unloaded -= OnUnloaded;
_descriptor.RemoveValueChanged(this, OnValueChanged);
}
}
regards.
Related
I created a editable ComboBox for searching(filtering) like Google. I am using the ActionHandler "KeyUp" and the first input is highlighted and overwritten. How can i disable the overwriting or highlighting?
private void CbInKuLi_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(cbInKuLi.ItemsSource);
itemsViewOriginal.Filter = ((o) =>
{
if (String.IsNullOrEmpty(cbInKuLi.Text)) return true;
else
{
DeKreditor x = (DeKreditor)o;
string filterText = cbInKuLi.Text;
if (x.Nummer.ToLowerInvariant().Contains(filterText)
|| (!string.IsNullOrWhiteSpace(x.Firma) && x.Firma.ToLowerInvariant().Contains(filterText))
|| (!string.IsNullOrWhiteSpace(x.Vorname) && x.Vorname.ToLowerInvariant().Contains(filterText))
|| (!string.IsNullOrWhiteSpace(x.Name) && x.Name.ToLowerInvariant().Contains(filterText)))
return true;
else
return false;
}
});
itemsViewOriginal.Refresh();
cbInKuLi.IsDropDownOpen = true;
}
XAML:
<ComboBox
x:Name="cbInKuLi"
StaysOpenOnEdit="True"
IsEditable="True"
IsTextSearchEnabled="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Grid.Row="0"
Grid.Column="1"
Margin="5,0,5,5"
SelectionChanged="CbInKuLi_SelectionChanged"
KeyUp="CbInKuLi_KeyUp"
TextOptions.TextFormattingMode="Ideal" />
The Text Highlight caused because of setting IsDropDownOpen to true.
The Editable ComboBox auto select the Text if it is Opened, so you could get the TextBox from the template of the ComboBox by its Name than set the selection length to zero at the end of the text.
private void CbInKuLi_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(cbInKuLi.ItemsSource);
itemsViewOriginal.Filter = ((o) =>
{
if (String.IsNullOrEmpty(cbInKuLi.Text)) return true;
else
{
Model x = (Model)o;
string filterText = cbInKuLi.Text;
if (x.Text.ToLowerInvariant().Contains(filterText))
return true;
else
return false;
}
});
itemsViewOriginal.Refresh();
cbInKuLi.IsDropDownOpen = true;
var textbox = (TextBox)cbInKuLi.Template.FindName("PART_EditableTextBox", cbInKuLi);
textbox.Select(textbox.Text.Length, textbox.Text.Length);
}
UPDATE:
From comments you can replace the last line by the following line and it is better than the original one:
textbox.CaretIndex = textbox.Text.Length;
I'm adding some TextBlock elements to Border elements in a StackPanel.
I'm adding and formating the text of the TextBlock by adding Inlines.
When clicked, I want to get the formated text of the TextBlock.Here is my code.
public void addText()
{
TextBlock myText = new TextBlock();
myText.Inlines.Add(new Bold(new Run("Hello ")));
myText.Inlines.Add("World!");
Border myBorder = new Border();
myBorder.Child = myText;
myBorder.MouseDown += new MouseButtonEventHandler(Border_Clicked);
myStackPanel.Children.Add(myBorder);
}
private void Border_Clicked(object sender, MouseButtonEventArgs e)
{
//Border senderBox = (Border)sender;
//TextBlock senderText = (TextBlock)senderBox.Child;
//Bold inline = (Bold) senderText.Inlines.ElementAt(0);
// How to Output "Hello "?
}
Border_Clicked should output "Hello ". As you can see I'm able to get to the bolded Text but how can I ouput it?
#Helen, There is a way to get the Text from the TextPointer using TextRange. Try this code
void myBorder_MouseDown(object sender, MouseButtonEventArgs e)
{
var senderBox = (Border)sender;
var senderText = (TextBlock)senderBox.Child;
var inline = (Bold)senderText.Inlines.ElementAt(0);
var textRange = new TextRange(inline.ContentStart, inline.ContentEnd);
Console.WriteLine(textRange.Text);
}
Is the problem to get text out of Bold element?
private void Border_Clicked(object sender, MouseButtonEventArgs e)
{
var border = (Border)sender;
var textBlock = (TextBlock)border.Child;
var bold = (Bold)textBlock.Inlines.ElementAt(0);
// How to Output "Hello "?
// try
var output = ((Run)bold).Text;
// or rather (because Bold is a wrapper)
var output = ((Run)bold.Inlines[0]).Text;
}
If you can add inline like this
myText.Inlines.Add(new Run("Bold text") { FontWeight = FontWeight.Bold });
then it's
var run = (Run)textBlock.Inlines[0];
var output = run.Text;
It is not possible to control Font characteristics in a MessageBox. I think you should consider to create a "custom MessageBox". Something like this:
<Window x:Class="WpfApplication1.CustomMessageBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight" MaxWidth="400">
<Grid x:Name="GridContent" Margin="10">
</Grid>
</Window>
So in its constructor you could send your Bold:
private Bold _text;
public CustomMessageBox(Bold formattedText)
{
_text = formattedText;
GridContent.Child = _text;
}
Using:
private void Border_Clicked(object sender, MouseButtonEventArgs e)
{
Border senderBox = (Border)sender;
TextBlock senderText = (TextBlock)senderBox.Child;
Bold inline = (Bold) senderText.Inlines.ElementAt(0);
var customMsgBox = new CustomMessageBox(inline);
customMsgBox.ShowModal();
}
Now, if you are not sure it will be always a Bold object, I suggest you to save your formatted text in XML and load it after. Take a look at this: showing formatted text
I have this XAML for acolumn into DataGrid
<DataGridTemplateColumn Header="% Deduccion Anticipo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay, StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay,StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The Stringformat applys as i expect, but muy problem is the user can fill it with any char alpha, number symbol, how can i do to prevent it, it is posible set an inputmask ?
I'm was trying with another StringFormats but any one of them work as I expect.
UPDATE: The column is currently binded to a Numeric property of my view model.
You can use the KeyDown event of a TextBox to intercept and filter out invalid values. You could even create your own derived TextBox and override OnKeyDown for a better encapsulated solution.
None of the built-in controls have the ability to specify an input mask. But, there are masked input controls out there on the internet for WPF. We are using the Telerik Rad Controls for WPF package and it has such a control. I use it in my application and it works very well.
you can achieve your requirement by using following methods.
Put the masked textbox in CellEditingTemplate and set the mask in that masked textbox.
Create the custom render based on your requirement and bind to the CellEditingTemplate.
After some research found this on another question:
Numeric Data Entry in WPF And #Brian Hinchey answer match with some of my needs.
Just add by myself some Culture validations for decimal numbers plus some editing and validation tools. Hope this help somebody else.
To use it:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<controls:NumericTextBox DecimalPlaces="2" DecimalSeparator="."/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
If no decimal places or separator are provided, it take CultureInfo.CurrentCulture parms
Here is the final code:
public class NumericTextBox : TextBox
{
#region Formato
private string previousText = "";
private bool ApplyingFormat = false;
private CultureInfo _CI = new CultureInfo(CultureInfo.CurrentCulture.LCID,true);
public CultureInfo CI
{
get { return _CI; }
set { _CI = value; }
}
private int _DecimalPlaces = 0;
/// <summary>
/// Numero de plazas decimales
/// </summary>
public int DecimalPlaces
{
get { return _DecimalPlaces; }
set { _DecimalPlaces = value; _CI.NumberFormat.NumberDecimalDigits = value; }
}
public Decimal DecimalValue = 0;
private string _DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
public string DecimalSeparator
{
get { return _DecimalSeparator; }
set { _DecimalSeparator = value; _CI.NumberFormat.NumberDecimalSeparator = _DecimalSeparator; }
}
//public string DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
#endregion
public NumericTextBox()
{
HorizontalContentAlignment = HorizontalAlignment.Right;
DataObject.AddPastingHandler(this, OnPaste);
}
private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
{
var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
if (isText)
{
var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
if (IsTextValid(text))
{
return;
}
}
dataObjectPastingEventArgs.CancelCommand();
}
private bool IsTextValid(string enteredText)
{
// If keyboard insert key is in toggled mode, and the actual insert point is Decimalseparator, we must avoid to overwrite it
if (SelectionStart == this.Text.IndexOf(DecimalSeparator)
& System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.Insert) == System.Windows.Input.KeyStates.Toggled)
{
SelectionStart += 1;
}
if (!enteredText.All(c => Char.IsNumber(c) || c == DecimalSeparator.ToCharArray()[0] || c == '-'))
{
return false;
}
//We only validation against unselected text since the selected text will be replaced by the entered text
var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);
if ( enteredText == DecimalSeparator && unselectedText.Contains(DecimalSeparator))
{
// Before return false, must move cursor beside Decimal separator
SelectionStart = this.Text.IndexOf(DecimalSeparator) + 1;
return false;
}
if (enteredText == "-" && unselectedText.Length > 0)
{
return false;
}
return true;
}
private bool ApplyFormat(TextChangedEventArgs e)
{
if (!ApplyingFormat)
{
ApplyingFormat = true;
int SelectionStartActual = SelectionStart;
string FinallText = this.Text;
if (!FinallText.Contains(DecimalSeparator) & DecimalPlaces > 0)
{
FinallText = String.Format("{0}{1}{2}", this.Text, DecimalSeparator, new string('0', DecimalPlaces));
}
bool state = Decimal.TryParse(FinallText, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint | NumberStyles.AllowTrailingSign, _CI, out DecimalValue);
DecimalValue = Math.Round(DecimalValue, DecimalPlaces);
if (DecimalValue == 0)
{
FinallText = "";
}
else
{
if (FinallText != DecimalValue.ToString(_CI))
{
FinallText = DecimalValue.ToString(_CI);
}
}
if (FinallText != this.Text)
{
this.Text = FinallText;
SelectionStart = SelectionStartActual;
}
previousText = this.Text;
ApplyingFormat = false;
return state;
}
else
{
return true;
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
e.Handled = !ApplyFormat(e);
base.OnTextChanged(e);
}
protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !IsTextValid(e.Text);
base.OnPreviewTextInput(e);
}
}
I need to highlight and manipulate an item of LongListSelector on the UI for the user.
I see (this) example on code samples but couldn't understand it well.
How can I change background of the inner StackPanel which belongs to the SelectedItem and add a TextBlock into it, programmatically in code behind?
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
To make the sample you linked work with a StackPanel
private void lls_SelectionChanged(object sender, SelectionChangedEventArgs e) {
var spList = new List<StackPanel>();
GetItemsRecursive<StackPanel>(lls, ref spList);
// Selected.
if (e.AddedItems.Count > 0 && e.AddedItems[0] != null) {
foreach (var sp in spList) {
if (e.AddedItems[0].Equals(sp.DataContext)) {
sp.Background = new SolidColorBrush(Colors.Green);
sp.Children.Add(new TextBlock { Text = "Hello" });
}
}
}
// Unselected.
if (e.RemovedItems.Count > 0 && e.RemovedItems[0] != null) {
foreach (var sp in spList) {
if (e.RemovedItems[0].Equals(sp.DataContext)) {
sp.Background = (SolidColorBrush)Resources["PhoneBackgroundBrush"];
sp.Children.RemoveAt(sp.Children.Count - 1);
}
}
}
}
I am not sure whether I understood your question correctly since I am new in windows phone development. Here is the code for changing the background of stackpanel and adding textblock to it programmatically.
enter code here
// Constructor
public MainPage()
{
InitializeComponent();
// change the background of stackpanel
StackPanel st = new StackPanel();
SolidColorBrush mysolidbrush = new SolidColorBrush();
mysolidbrush.Color = Color.FromArgb(255, 100,100,10); // RGB color
st.Background = mysolidbrush;
// Adding textblock to the stackpanel
TextBlock txtblk = new TextBlock();
st.Children.Add(txtblk);
}
Best,
B
I have a user control which creates an animation of scrolling text and on my main window I call it like this:
xmlns:mar="clr-namespace:WpfApplication4.AppPages"
<mar:Feed Background="DarkGray" FontSize="12" MarqueeTimeInSeconds="8"
Foreground="Gray" Margin="7,383,711,6" MarqueeContent="Live Feed"
MarqueeType="TopToBottom"></mar:Feed>
The code for the user control looks like this:
MarqueeType _marqueeType;
public MarqueeType MarqueeType
{
get { return _marqueeType; }
set { _marqueeType = value; }
}
public String MarqueeContent
{
set { tbmarquee.Text = value; }
}
private double _marqueeTimeInSeconds;
public double MarqueeTimeInSeconds
{
get { return _marqueeTimeInSeconds; }
set { _marqueeTimeInSeconds = value; }
}
public Feed()
{
InitializeComponent();
canMain.Height = this.Height;
canMain.Width = this.Width;
this.Loaded += new RoutedEventHandler(Feed_Loaded);
}
void Feed_Loaded(object sender, RoutedEventArgs e)
{
StartMarqueeing(_marqueeType);
}
public void StartMarqueeing(MarqueeType marqueeType)
{
TopToBottomMarquee();
}
private void TopToBottomMarquee()
{
double width = canMain.ActualWidth - tbmarquee.ActualWidth;
tbmarquee.Margin = new Thickness(width / 2, 0, 0, 0);
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -tbmarquee.ActualHeight;
doubleAnimation.To = canMain.ActualHeight;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(_marqueeTimeInSeconds));
tbmarquee.BeginAnimation(Canvas.TopProperty, doubleAnimation);
}
public enum MarqueeType
{
TopToBottom
}
On the main window I set the xaml MarqueeContent="Live Feed" like so but how can I set the content in the code behind and how can I set multiple MarqueeContents?
For instance even if I was able to set the MarqueeContent from code behind and I added multiple items to it, it will no doubt just add it one after the other like the text your reading just now, I need it so each item I add has at least a paragraph spacing if that makes sense.
To give a visual idea on it you can see it here (TopDown):
http://www.codeproject.com/Articles/48267/Making-a-Simple-Marquee-Text-Control-Drip-Animatio
I need it so I can load multiple strings into it. And that each string of text added is separated by a paragraph.
If it is only about adding multiple lines of text to one moving block, you could simply add line breaks between the lines:
textBlock.Text = "A line of text.\n\nAnother line of text.";
Or you can do the same with Inlines:
textBlock.Inlines.Add(new Run("A line of text."));
textBlock.Inlines.Add(new LineBreak());
textBlock.Inlines.Add(new LineBreak());
textBlock.Inlines.Add(new Run("Another line of text."));