WPF Rich text box underline - wpf

I have strange problem with my richtextbox.
I want to detect when text is Bold, Italic etc.
E.g
if (richTextBox.Selection.GetPropertyValue(TextElement.FontStyleProperty).ToString() == "Italic") // Pochylenie
{
heremycode
}
If we use
MessageBox(richTextBox.Selection.GetPropertyValue(TextElement.FontStyleProperty).ToString());
I get Italic. I want do exacly the same with underline and strikethrough, because I can't use
TextBlock.TextDecorationsProperty.ToString(),
because i get only name of method i think? Nothink like "italic", or "bold" just "FontStyleProperty".
private void richTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
....
if (richTextBox.Selection.GetPropertyValue(TextElement.FontStyleProperty).ToString() == "Italic"
{
backgroundP.Stroke = Brushes.Black;
backgroundP.Fill = Brushes.LawnGreen;
p = true;
}
TextRange selectionRange = new TextRange(richTextBox.Selection.Start, richTextBox.Selection.End);
if (selectionRange.GetPropertyValue(Underline.TextDecorationsProperty).Equals(TextDecorations.Underline))
{
MessageBox.Show("Wow We did it :)");
backgroundUnderline.Stroke = Brushes.Black;
}
}
And XAML Code:
<Grid x:Name="Center" Margin="10,231,10,10">
<Rectangle Fill="#B2F4F4F5" Stroke="Black" Margin="1,0,-1,0"/>
<Label x:Name="labelNotepad" Content="Notepad" HorizontalAlignment="Left" VerticalAlignment="Top" Width="385" FontWeight="Bold" Background="#FFC1FCFF" FontSize="21.333" Height="56" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="2,1,0,0" BorderThickness="0,0,1,0"/>
<RichTextBox x:Name="richTextBox" Margin="1,58,0,0" FontSize="16" BorderThickness="1,2,1,1" BorderBrush="Black" UseLayoutRounding="False" VerticalScrollBarVisibility="Auto" Background="#7FFFFFFF" SelectionChanged="richTextBox_SelectionChanged">
<FlowDocument/>
</RichTextBox>

Have you tried this:
TextRange selectionRange = new TextRange(RichTextControl.Selection.Start, RichTextControl.Selection.End);
if (selectionRange.GetPropertyValue(Inline.TextDecorationsProperty) == TextDecorations.Underline)
{
}
this should work, you get only the Object name beacause you donĀ“t set the dependency property what you want to have as a string. The decoration can be Underline etc you must declarate what you want to check

We need to see more of your code because SeeuD1's suggestion should work. However, it will only work if the entire selection is underlined.
If you need to see if there is ANY underlined text in the selection, not ONLY, then you need to check all the inline objects in the selection.
In this example I will only check paragraphs in your FlowDocument:
foreach (var block in RichTextBox.Document.Blocks.Where(x => selection.Start.CompareTo(x.ContentEnd) < 0 && selection.End.CompareTo(x.ContentStart) > 0))
{
var paragraph = block as Paragraph;
if (paragraph != null)
{
foreach (var selectedInline in paragraph.Inlines.Where(x => selection.Start.CompareTo(x.ContentEnd) < 0 && selection.End.CompareTo(x.ContentStart) > 0))
{
if (selectedInline.GetPropertyValue(Inline.TextDecorationsProperty) == TextDecorations.Underline)
{
MessageBox.Show("Wow We did it :)");
}
}
}
}

Related

Make wpf button fonts match at runtime

I have several buttons, like this:
<Button Name="btnContent" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Viewbox MaxWidth="100" StretchDirection="Both">
<TextBlock Text="Content" ></TextBlock>
</Viewbox>
</Button>
<Button Name="btnMoreContent" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Viewbox MaxWidth="100" StretchDirection="Both">
<TextBlock Text="More Content" ></TextBlock>
</Viewbox>
</Button>
The font scales to fit the buttons. How can I grab the text size / scale value of the button with the smallest text at runtime and set them all to that size?
I tried:
double FontSize = btnContentButton.FontSize;
if (FontSize < btnLongerContentButton.FontSize)
{
FontSize = btnLongerContentButton.FontSize;
}
btnContentButton.FontSize = FontSize;
btnLongerContentButton.FontSize = FontSize;
But this doesn't work, because I never actually changed the font size - It sets them all to 12.
Try the suggested solutions in this link and see if they can solve the problem.
However, you might want to try this one too: Handle Load event, find all TextBlocks with parent of type ViewBox (You might check other conditions or set proper names, to avoid further problems here), adjust their Width, properly, based on the Width of the one with the longest Text:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
List<TextBlock> tbs = new List<TextBlock>();
TextBlock longestText = null;
foreach (TextBlock t in FindVisualChildren<TextBlock>(this))
{
if (t.Parent is Viewbox)
{
tbs.Add(t);
if (longestText == null)
longestText = t;
else if (t.Text.Length > longestText.Text.Length)
longestText = t;
}
}
double a = longestText.ActualWidth / longestText.ActualHeight;
foreach (TextBlock tb in tbs)
{
if (tb == longestText)
continue;
tb.Width = a * tb.ActualHeight;
}
}
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
FindVisualChildren method is from here.
Hope it helps.

Devxpress grid currency formatting

I'm using Devxpress v13.1 and not allowed to upgrade it.
I am trying to render a devxpress grid from a dataset. I want $400.0000 to display as $400.00 and can't get it to work.
I have the following code:
public MainWindow{
DataSet TransactionList = GetDataFromXML();// Loads XML to DS
TransactionGrid.ItemsSource = TransactionList.Tables[0];
TransactionGrid.CustomColumnDisplayText += TransactionGrid_CustomColumnDisplayText;
}
void TransactionGrid_CustomColumnDisplayText(object sender, DevExpress.Xpf.Grid.CustomColumnDisplayTextEventArgs e)
{
if (e.Column.FieldName == "Amount1")
{
//e.Column.DisplayTemplate =
e.DisplayText = String.Format("{0:0.00}", e.Value);
}
}
xaml code:
<dxg:GridControl Name="TransactionGrid" HorizontalAlignment="Left" Height="Auto" Width="Auto" >
<dxg:GridControl.View >
<dxg:TableView AllowEditing="False"></dxg:TableView>
</dxg:GridControl.View>
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Amount1" Header="Amount1" Width="80" >
</dxg:GridColumn>
</dxg:GridControl.Columns>
</dxg:GridControl
>
I used the TGrid_CustomColumnDisplayText event to achieve the results. Trying to implement StringFormat="c2" didnt work at the xaml level. I had to Call the statement below in the constructor of the xaml page.
TGrid.CustomColumnDisplayText += TGrid_CustomColumnDisplayText;
Event is as below-
void Tgrid_CustomColumnDisplayText(object sender,
DevExpress.Xpf.Grid.CustomColumnDisplayTextEventArgs e)
{
CultureInfo ciUsa = new CultureInfo("en-US");
if (e.Column.FieldName == "Amount")
{
e.DisplayText = String.IsNullOrEmpty(e.Value.ToString()) ? String.Empty : String.Format(ciUsa, "{0:c2}", Convert.ToDecimal(e.Value));
}
}

How can I bind a context menu on a LineSymbol in ESRI?

I have created a ControlTemplate for a LineSymbol:
<esri:SimpleLineSymbol
x:Key="PolylineSymbol"
Width="3"
>
<esri:SimpleLineSymbol.ControlTemplate>
<ControlTemplate>
<Grid
>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
...
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
...
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Path
x:Name="Element" Fill="{x:Null}"
Stroke="Navy" StrokeThickness="3"
StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.ContextMenu>
<ContextMenu
x:Name="popUpMenu"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type esri:Graphic}}}">
<MenuItem
x:Name="miSelect"
Header="Select"
IsCheckable="True"
IsChecked="{Binding Selected, FallbackValue=False}"
/>
...
</ContextMenu>
</Path.ContextMenu>
</Path>
</Grid>
</ControlTemplate>
</esri:SimpleLineSymbol.ControlTemplate>
</esri:SimpleLineSymbol>
Everything works well, except the binding in IsChecked on the "Select" menu item: Since neither Symbol, nor Graphic inherits from FrameworkElement no binding expression will take me from here to the Contained Graphic of this SimpleLineSymbol.
I have also tried a Click event (which gives a sender, a command (which supports a parameter) or a MouseRightButtonDown event (on the graphic,) - no method takes me from the right-clicked point on the path of the Symbol to the containing Graphic...
The DataContext of the Menu looks OK in the designer of VS2012, but at run time it does not works, since the Menu is inside a path defined in the ControlTemplate of a Symbol which is not a FrameworkElement!
I have added a name for the ContextMenu, but I am not able to retrieve it from the ViewModel (where I create the graphic and the symbol; if I were able to do that, I would be able to add the desired datacontext in code:
var graphic = new Graphic { Symbol = Resources["PolylineSymbol"] as SimpleLineSymbol;
var menu = graphic.Symbol.ControlTemplate.FindName("popUpMenu", graphic.Symbol); // ???
menu.DataContext = graphic;
)
Any Ideas, please?
If I understand your problem correctly, it seems as though you have a common problem in WPF. The solution is to utilise a Tag property of your Path to 'pass' the DataContext through to the ContextMenu using the ContextMenu.PlacementTarget property. This Gets or sets the UIElement relative to which the ContextMenu is positioned when it opens. Try this:
<Path x:Name="Element" Fill="{x:Null}" Stroke="Navy" StrokeThickness="3"
StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round"
Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type
esri:Graphic}}}"><!--Use Binding.Path that you need for data here-->
<Path.ContextMenu>
<ContextMenu x:Name="popUpMenu" DataContext="{Binding PlacementTarget.Tag,
RelativeSource={RelativeSource Self}}"><!--Use PlacementTarget.Tag-->
<MenuItem x:Name="miSelect" Header="Select" IsCheckable="True"
IsChecked="{Binding Selected, FallbackValue=False}" />
...
</ContextMenu>
</Path.ContextMenu>
</Path>
The solution was to implement the Opened even of the Context menu. In the code behind I assign the instance of the view model on its DataContext.
<Path.ContextMenu>
<ContextMenu
Opened="PopUpMenu_OnOpened"
>
code behind:
private void PopUpMenu_OnOpened(object sender, RoutedEventArgs e)
{
var menu = sender as ContextMenu;
if (menu != null)
{
menu.DataContext = ViewModel;
}
}
Another challenge was to get the clicked graphic and the clicked point.
The solution was to create properties in the View model and assign both on LeftMouseDown and RightMouseDown.
private Graphic GetPolylineGraphic(ESRI.ArcGIS.Client.Geometry.Geometry geometry = null)
{
var drawLayer = Model.GetDrawLayer(MyMap, "Polyline");
var graphic = new Graphic
{
// clone the resourced PolylineSymbol (from Model)
Symbol = new SimpleLineSymbol
{
Color = PolylineSymbol.Color,
Width = PolylineSymbol.Width,
ControlTemplate = PolylineSymbol.ControlTemplate
}
};
if (geometry != null) graphic.Geometry = geometry;
graphic.MouseLeftButtonDown += GraphicOnMouseLeftButtonDown;
graphic.MouseRightButtonDown += GraphicOnMouseRightButtonDown;
drawLayer.Graphics.Add(graphic);
return graphic;
}
private Graphic m_clickedGraphic;
public Graphic ClickedGraphic
{
get { return m_clickedGraphic; }
set
{
if (!Equals(m_clickedGraphic, value))
{
m_clickedGraphic = value;
OnPropertyChanged(value);
}
}
}
private MapPoint m_clickedPoint;
public MapPoint ClickedPoint
{
get { return m_clickedPoint; }
set
{
if (m_clickedPoint != value)
{
m_clickedPoint = value;
OnPropertyChanged(value);
}
}
}
private void GraphicOnMouseRightButtonDown(object sender, MouseButtonEventArgs args)
{
//// This does not work because GraphicElement is internal!!!
//var s = args.Source;
//ClickedGraphic = ((GraphicElement)(e.Source)).Graphic;
//ClickedPoint = ((GraphicElement)(e.Source)).Origin;
ClickedGraphic = sender as Graphic;
ClickedPoint = MyMap.ScreenToMap(args.GetPosition(MyMap));
//// not here - else context menu won't pop!
//args.Handled = true;
}
private void GraphicOnMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
{
var g = sender as Graphic;
if (g != null)
{
ClickedGraphic = g;
ClickedPoint = MyMap.ScreenToMap(args.GetPosition(MyMap));
// select/unselect the graphic on left click
if (g.Selected) g.UnSelect();
else g.Select();
args.Handled = true;
}
}
To make everything work, I had to clone the symbol.

why the name of the Controls in ItemsControl not displaying in Codebehind file in Wpf

i Created simple sample using the ItemsControl and DataTemplate.. i want to bind the values using the C# code in textblocs.But i didn't get the textblock names and Datatemplate names in Code behind file please tell me why.. What to do to get the names of the controls ?
<ItemsControl ItemsSource="{Binding Path=.}" >
<ItemsControl.ItemTemplate>
<DataTemplate x:Name="datatemp">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Textblock1" Text="{Binding }" FontWeight="Bold" ></TextBlock>
<TextBlock Text=", " />
<TextBlock Text="{Binding }" x:Name="Textblock2"></TextBlock>
<TextBlock Text=", " />
<TextBlock Text="{Binding }" x:Name="Textblock3"></TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
but here in Code file Textblock1 and other names not dispalying even i used the "Name" only Instead of "x:Name "
No member will be generated for the DataTemplate. A datatemplate is just used for instantiating items dynamically at runtime, so the Controls don't even exist until you add items to your ItemsControl, and even then i think the names of individual controls inside the DataTemplate are just useful for usage from inside the DataTemplate's markup.
You can generate names, if needed when the ItemsControl is loaded.
private void OnPopupItemsLoaded(object sender, RoutedEventArgs e)
{
var itemsControl = sender as ItemsControl;
itemsControl.ApplyTemplate();
var numItems = itemsControl.ItemContainerGenerator.Items.Count();
for (var i = 0; i < numItems; i++)
{
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i);
textBlock = FindVisualChild<TextBlock>(container);
if (textBlock != null)
{
textBlock.Name = SanitizeName(textBlock.Text);
textBlock.Uid = $"Item{i}";
}
}
}
private static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null)
{
return childItem;
}
}
}
// None found
return null;
}
// FrameworkeElement.Name must start with an underscore or letter and
// only contain letters, digits, or underscores.
private string SanitizeName(string textString)
{
// Text may start with a digit
var sanitizedName = "_";
foreach (var c in textString)
{
if (char.IsLetterOrDigit(c))
{
sanitizedName += c;
}
else
{
sanitizedName += "_";
}
}
return sanitizedName;
}

wpf binding when using datatemplate

ok currently i have this piece of code:
<TabItem Style="{DynamicResource MyStyle" x:Name="TabCustomers" Padding="0,1,4,1"
Header={Binding Path=customersHeader}/>
Now i want to add an icon there so I do (by removing the header above):
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{StaticResource customers}"/>
<TextBlock x:Key="textblock" Margin="4,0,0,0"
Text="{Binding Path=customersHeader}"/>
</StackPanel>
</TabItem.Header>
So far it's ok.
I would like to generalize this using a datatemplate. I assume i have to do this in my resource dictionary:
<DataTemplate x:Key="TabItemCustomersTemplate" DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{StaticResource customers}"/>
<TextBlock x:Key="textblock" Margin="4,0,0,0"
Text="{Binding Path=customersHeader}"/>
</StackPanel>
</DataTemplate>
and change this in my tabitem declaration:
<TabItem ... HeaderTemplate="{StaticResource TabItemCustomersTemplate}".../>
So i run into the following issues and questions:
1) binding doesnt work, why?
2) how can i access textblock from c#?
3) how can i generalize this so i dont have to copy this over and over again for different tab items (or other controls for the matter) so that i can pass my own text and image source each time? For example you might use this to create an image button and if you have 20 buttons the code becomes messy.
Any ideas?
Thank you.
if you template the header in a
tabitem, you do not need to set the
data type of the template. the
header is a property of the tab
item, it is actually a property of
type object, you can put anything in
there.
try removing the DataType="{x:Type
TabItem}" and see if it works.
you should not need to access the
textblock from c#, you should make
do with the binding system. place a
custom object in your header. then
bind this object to your textblock
then adjust the object and it will
manipulate the textblock. getting at
an element is always hard if it is
contained in a data template. you
should not need to. if you find
yourself walking the visual tree to
find a visual element you are doing
things the hard way
you can generalise this by following
suggestion 2, using a custom object,
removing the x:Key of your data
template and setting its DataType to
be the type of your custom object.
then wherever your custom object
appears you will get it data
templated properly
Try this, This is working for me
<Window.Resources>
<!-- <BitmapImage x:Key="customers" UriSource="einstein.jpg"/>-->
<DataTemplate x:Key="TabItemCustomersTemplate">
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{Binding Path=Customers}"/>
<TextBlock Margin="4,0,0,0" x:Name="txt" Text="{Binding Path=CustomersHeader}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl Name="mytabcontrol">
<TabItem x:Name="TabCustomers" Padding="0,1,4,1" Header="{Binding}" HeaderTemplate="{StaticResource TabItemCustomersTemplate}">
<Label Content="myContent" Background="Red"/>
</TabItem>
</TabControl>
</Grid>
in code behind
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
var lst = new List<People>();
lst.Add(new People() { CustomersHeader = "My Customer" });
this.DataContext = lst;
}
}
public class People
{
public string CustomersHeader { get; set; }
public BitmapImage Customers { get; set; }
}
Further you can find your textblock in code behind using this
TabPanel tabPanel = GetVisualChild<TabPanel>(mytabcontrol);
if (tabPanel != null)
{
foreach (UIElement element in tabPanel.Children)
{
TabItem tabItem = element as TabItem;
var image = FindNameFromHeaderTemplate<TextBlock>(tabItem, "txt");
}
}
public static T FindNameFromHeaderTemplate<T>(TabItem tabItem, String name) where T : UIElement
{
if (tabItem == null)
{
throw new ArgumentNullException("container");
}
if (tabItem.HeaderTemplate == null)
{
return null;
}
ContentPresenter contentPresenter = GetVisualChild<ContentPresenter>(tabItem);
if (contentPresenter == null)
{
return null;
}
T element = tabItem.HeaderTemplate.FindName(name, contentPresenter) as T;
return element;
}
public static T GetVisualChild<T>(Visual referenceVisual) where T : Visual
{
Visual child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
{
child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
if (child != null && child.GetType() == typeof(T))
{
break;
}
else if (child != null)
{
child = GetVisualChild<T>(child);
if (child != null && child.GetType() == typeof(T))
{
break;
}
}
}
return child as T;
}

Resources