WPF Insert variable in TextBlock - c#

Is it possible to bind "AMOUNT" with it's value (i.e. update with corresponding global variable) using only XAML? If not, what i have write to replace AMOUNT with my var before showing the page?
http://i.imgur.com/SDrV0rs.png
<TextBlock Height="231" Canvas.Left="120" TextWrapping="Wrap" Canvas.Top="459" Width="840"
FontFamily="Neo Sans Pro" FontSize="48"
Foreground="#FF006CB7"
VerticalAlignment="Top" HorizontalAlignment="Left" TextAlignment="Center">
<Run Text="Для перечисления "/>
<Run FontWeight="Bold" Text="AMOUNT"/>
<Run Text=" рублей в помощь детям с помощью банковской карты, пожалуйста, следуйте инструкции:"/>
</TextBlock>

What you need is a binding to a variable in your code-behind.
Text="{Binding AMOUNT}"
If this is - as you describe - a "global variable", you can bind like so:
Text="{x:Static wpfApplication1:Globals.Amount}"
The global variable definition could look like this:
public class Globals
{
public static string Amount = "5000";
}
Note that the Text property of your text box requires a string.

Using MVVM; in very broad strokes :
Create a class with a string property: e.g.
public class MyViewModel
{
public string Amount { get { return "..."; } }
}
Assign an instance of the class above to the DataContext of the view.
var viewModel = new MyViewModel();
view.DataContext = viewModel;
Using a binding expression in the XAML
...TextBlock Text="{Binding Amount}"... />

Related

TextBlock with text highlighting

Faced the need to select a fragment of text in TextBlock, namely certain keywords on which the ListBox was filtered, this text block itself and containing
XAML variant, title property is not bound
<ListBox Name="ProcedureList" ItemsSource="{Binding Path=ProceduresView.View}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Name="ProcedurePanel" PreviewMouseDown="ProcedurePanel_OnPreviewMouseDown">
<DockPanel Width="{c:Binding ElementName=MainPanel, Path=Width-40}">
<!--<TextBlock Name="MainText" TextWrapping="Wrap" FontSize="16" Text="{Binding Path=title}" HorizontalAlignment="Left" />-->
<htb:HighlightTextBlock Name="MainText" TextWrapping="Wrap" FontSize="16" Text="{Binding Path=title}" HorizontalAlignment="Left">
<htb:HighlightTextBlock.HighlightRules>
<htb:HighlightRule
IgnoreCase="{Binding IgnoreCase, Source={StaticResource SourceVm}}"
HightlightedText="{Binding Path=title, Converter={StaticResource getFilter}}">
<htb:HighlightRule.Highlights>
<htb:HighlightBackgroung Brush="Yellow"/>
</htb:HighlightRule.Highlights>
</htb:HighlightRule>
</htb:HighlightTextBlock.HighlightRules>
</htb:HighlightTextBlock>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A component written by our compatriot with open source is used
Component
Description of component
The commented code is an old TexBlock with no selection
The new HighlightTextBlock component perfectly selects the text if you use a static resource, as in the example, but when I try to bind it to the current text it can not find this field :(, I'm new in WPF help figure it out
HightlightedText="{Binding Path=title, Converter={StaticResource getFilter}}"
How correctly to anchor this property to title?
DataContext structure
public ObservableCollection<Procedure> Procedures { set; get; }
public CollectionViewSource ProceduresView { set; get; } = new CollectionViewSource();
....
Procedures = new ObservableCollection<Procedure>();
ProceduresView.Filter += Procedures_Filter;
ProceduresView.Source = Procedures;
....
public class Procedure : ObservableObject
{
....
public String title { get; set; }
....
}
....
// Simple filtering
void Procedures_Filter(object sender, FilterEventArgs e)
{
Procedure procedure = (Procedure) e.Item;
Boolean flag = false;
if (!string.IsNullOrEmpty(filter))
{
Setting.Filter sfilter = new Setting.Filter();
sfilter.type = "искать везде";
sfilter.text = filter;
ObservableCollection<Setting.Filter> arr = new ObservableCollection<Setting.Filter>();
arr.Add(sfilter);
if (Utils.AssignedProcedureFromFilter(procedure, arr)) flag = true;
}
else flag = true;
e.Accepted = flag;
}
Video with problem description
Simplified project emitting my functional
On the Russian-speaking forum they explained to me that:
Your case, in fact, is more serious. DataContext you, apparently, the
right one. But your Binding expression is inside the HighlightRules
property setter, which is not part of the visual tree (because it is
not available as a Child element of your control). And elements that
are not inside the visual tree, participate in bindings are only
limited: they do not inherit DataContext, nor access by name through
ElementName. As a solution, bind to an element via x: Reference. In my
(heavily cut) test case, HightlightedText = "{Binding Path =
DataContext.title, Source = {x: Reference MainText}} is triggered."
But, if directly replaced by this, a strange error works: 'Can not
call MarkupExtension. ProvideValue because of a cyclic dependency. The
properties inside the MarkupExtension can not reference objects that
reference the MarkupExtension result.
The workaround for the error was found here: you need to put your element in resources. We get this:
XAML, modified according to the recommendations
<ListBox Name="ProcedureList" ItemsSource="{Binding Path=ProceduresView.View}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Name="ProcedurePanel" PreviewMouseDown="ProcedurePanel_OnPreviewMouseDown">
<DockPanel Width="{c:Binding ElementName=MainPanel, Path=Width-40}">
<!--<TextBlock Name="MainText" TextWrapping="Wrap" FontSize="16" Text="{Binding Path=title}" HorizontalAlignment="Left" />-->
<htb:HighlightTextBlock Name="MainText" TextWrapping="Wrap" FontSize="16"
Text="{Binding Path=title}" HorizontalAlignment="Left">
<htb:HighlightTextBlock.Resources>
<htb:HighlightRule x:Key="HR"
IgnoreCase="{Binding IgnoreCase, Source={StaticResource SourceVm}}"
HightlightedText="{Binding Path=DataContext.title, Source={x:Reference MainText}, Converter={StaticResource getFilter}}">
<htb:HighlightRule.Highlights>
<htb:HighlightBackgroung Brush="Yellow"/>
</htb:HighlightRule.Highlights>
</htb:HighlightRule>
</htb:HighlightTextBlock.Resources>
<htb:HighlightTextBlock.HighlightRules>
<htb:HighlightRulesCollection>
<StaticResource ResourceKey="HR"/>
</htb:HighlightRulesCollection>
</htb:HighlightTextBlock.HighlightRules>
</htb:HighlightTextBlock>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I was given advice on the restructuring of XAML, through resources, this partially solved the problem (I successfully got the title text in the converter), but the element ceased to perform its functions (allocation) During the discussion, it was suggested that the component itself should be finalized
#iRumba: In theory, the whole trick should not be necessary if you put
the HighlighRule collection (also) in a visual tree. Then the
DataContext will be automatically inherited and on idea the binding
through ElementName too will work.
#iRumba: I do not remember exactly. It seems, it is necessary to
specify to add all HighlightRule as LogicalChildren (for this purpose
on idea it is necessary to redefine protected internal override
IEnumerator LogicalChildren). This is a complicated, advanced
technique, yes.
Sorry for Google Translator
Found a solution
public class SearchHightlightTextBlock : TextBlock
{
public SearchHightlightTextBlock() : base() { }
public String SearchText
{
get { return (String)GetValue(SearchTextProperty); }
set { SetValue(SearchTextProperty, value); }
}
private static void OnDataChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
TextBlock tb = (TextBlock)source;
if (tb.Text.Length == 0)
return;
string textUpper = tb.Text.ToUpper();
String toFind = ((String)e.NewValue).ToUpper();
int firstIndex = textUpper.IndexOf(toFind);
String firstStr = "";
String foundStr = "";
if (firstIndex != -1)
{
firstStr = tb.Text.Substring(0, firstIndex);
foundStr = tb.Text.Substring(firstIndex, toFind.Length);
}
String endStr = tb.Text.Substring(firstIndex + toFind.Length,
tb.Text.Length - (firstIndex + toFind.Length));
tb.Inlines.Clear();
tb.FontSize = 16;
var run = new Run();
run.Text = firstStr;
tb.Inlines.Add(run);
run = new Run();
run.Background = Brushes.Yellow;
run.Text = foundStr;
tb.Inlines.Add(run);
run = new Run();
run.Text = endStr;
tb.Inlines.Add(run);
}
public static readonly DependencyProperty SearchTextProperty =
DependencyProperty.Register("SearchText",
typeof(String),
typeof(SearchHightlightTextBlock),
new FrameworkPropertyMetadata(null, OnDataChanged));
}
Use
<parser:SearchHightlightTextBlock SearchText="{Binding Path=title, Converter={StaticResource getFilter}}" Text="{Binding title}"/>

How to change TextBlock Text Binding in C#

I'm working in huge application and I have one small problem
My Application has two languages (Arabic / English).
I have ComboBox And I would like to change the display content according to the language.
This is my ComboBox XAML:
<ComboBox x:Name="cmbCustomerGroup" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5"
Margin="2" SelectedValuePath="CustomerGroupId" Validation.Error="Validation_Error"
SelectedValue="{Binding Path=CustomerGroupId, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True}">
<!--<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>-->
</ComboBox>
This is my method:
private void FillCustomerGroups()
{
var oClsCustomers = new ClsCustomerGroups();
var lstCustGrps = oClsCustomers.GetData();
cmbCustomerGroup.ItemsSource = lstCustGrps.ToList<TbCustomerGroups>();
cmbCustomerGroup.DisplayMemberPath = Helper.CurrLang == Helper.SystemLanguage.Arabic ? "CustomerGroupAName" : "CustomerGroupEName";
cmbCustomerGroup.SelectedValuePath = "CustomerGroupId";
}
I got this result:
This is my database:
This usually occurs when DisplayMemberPath is set wrong, or bindable property is not a string and has no overriden ToString() method.
Try add new property to your TbCustomerGroups, for example CurrentGroupName like this
public string CurrentGroupName => Helper.CurrLang == Helper.SystemLanguage.Arabic ? CustomerGroupAName : CustomerGroupEName;
Then set cmbCustomerGroup.DisplayMemberPath = "CurrentGroupName"
Also check that CustomerGroupAName and CustomerGroupEName are strings or have ToString() method
UPDATE
Also don't use <ComboBox.ItemTemplate> if you use DisplayMemberPath

Can't edit TextBlock Text with caliburn micro dynamically

This might have been answered before.
I am trying to edit my TextBlock dynamically from an object that has a string.
However. It doesn't seem to be updated from the View. But the value is updated. Just that it doesn't display it. Is there any way for that? Is there a repaint method?
What should I do?
Code:
ViewModel:
private String title = "";
public string Title { get { return title; }
set
{
title = value;
NotifyOfPropertyChange(() => Title);
}
}
View.XAML:
<TextBlock x:Name="Title"
Text="{Binding Path=Title, Mode=TwoWay}"
Grid.Row="2"
VerticalAlignment="Top"
FontSize="18"
Grid.ColumnSpan="3"
TextAlignment="Center"
FontWeight="Light"/>
It looks like the solution here is to use Caliburns EventAggregator to communicate with several VM. This was the solution I came up with and now it works :)

Binding to RichTextBox Blocks property

I would like to bind directly to the Blocks property of a RichTextBox in my Xaml. This is not possible as the Blocks property is read only. I can bind directly to an individual run:
<RichTextBox x:Name="MyRichTextBox" FontSize="36" Margin="10" Foreground="White">
<Paragraph>
<Run Text="{Binding MyObject.Text}" Foreground="Yellow"/>
<Run Text="{Binding MyObject.Text}" Foreground="Cyan"/>
</Paragraph>
</RichTextBox>
I would like to do something like:
<RichTextBox x:Name="MyRichTextBox" Blocks="{Binding MyObject.RichTextBlocks}" FontSize="36" Margin="10" Foreground="White"/>
Particularly as I don't know in advance how many blocks will be returned from the binding object.
Is the correct way to achieve this to create an Attached Behaviour for the RichTextBox with a RichTextBlocks property that when being set enumerates through the blocks and calls RichTextBox.Blocks.Add() for each one?
I am new to C#, .NET and XAML so please excuse the elementary question and a simply explained answer would be greatly appreciated.
With the pointers from #Nogard and the other post, I created my own class with a Dependency Property called RichText. Have posted here in case it is of use to anyone else.
public class MyRichTextBox : RichTextBox
{
public static readonly DependencyProperty RichTextProperty = DependencyProperty.Register("RichText", typeof(Paragraph), typeof(MyRichTextBox), new PropertyMetadata(null, RichTextPropertyChanged));
public Paragraph RichText
{
get
{
return (Paragraph)GetValue(RichTextProperty);
}
set
{
SetValue(RichTextProperty, value);
}
}
private static void RichTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
MyRichTextBox richTextBox = (MyRichTextBox)dependencyObject;
Paragraph paragraph = (Paragraph)dependencyPropertyChangedEventArgs.NewValue;
// Remove any existing content from the text box
richTextBox.Blocks.Clear();
// Add the paragraph to the text box
richTextBox.Blocks.Add(paragraph);
}
}
}
and added this to my xaml...
<sub:MyRichTextBox x:Name="MyRichTextOverlay" RichText="{Binding CurrentOverlay.RichTextParagraph}" VerticalAlignment="Top" FontSize="36" Margin="10" Foreground="White" HorizontalAlignment="Center" TextWrapping="Wrap" TextAlignment="Center"/>

Rich formatting of text in a TextBlock using only DataBinding in XAML

I am trying to format a Tweet using Data Binding. What I need to do is split the Text value of the tweet based on what type of content it is.
text = "This is a Tweet with a hyperlink http://www.mysite.com"
I need to add some color formatting to the http://... portion of the text value.
Here's the kicker, I'd like to do this using only XAML Data Binding.
<TextBlock x:Name="Tweet1" FontWeight="Bold" Height="207.236"
LineHeight="55" TextAlignment="Left" TextWrapping="Wrap"
Width="1614.646" Text="{Binding XPath=/statuses/status[2]/text}"
FontSize="56" FontFamily="Segoe Book"
Foreground="{DynamicResource TextColor-Gray}" />
// needs to end up looking like
<TextBlock x:Name="Tweet1" FontWeight="Bold" ... FontSize="56" FontFamily="Segoe Book">
<Run Foreground="{DynamicResource TextColor-Gray}" >This is a Tweet with a hyperlink</Run>
<Run Foreground="{DynamicResource TextColor-Pink}" >http://www.mysite.com</Run>
</TextBlock>
Here is a Regex I could use to split the text value, but I'm trying to use strictly DataBinding.
Regex regUrl = new Regex(#"/http:\/\/\S+/g");
Suggestions?
I'm using MVVMLight. What I've done is to capture the Loaded event of the TextBlock, and route it to a "converter".
using System.Collections.Generic;
using System.Windows.Documents;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
namespace Converters
{
public class MyInlineConverter
{
public RelayCommand<TextBlock> ConvertTextToInlinesCommand { get; private set; }
public MyInlineConverter()
{
ConvertTextToInlinesCommand = new RelayCommand<TextBlock>(textBlock => convertTextToInlines(textBlock));
}
private static void convertTextToInlines(TextBlock textBlock)
{
foreach (Run run in textToInlines(textBlock.Text))
textBlock.Inlines.Add(run);
}
private static IEnumerable<Run> textToInlines(string text)
{
List<Run> retval = new List<Run>();
// Perform your conversion here.
return retval;
}
}
}
If you add an instance of this class to your static resources, like so:
<converters:TMTInlineConverter x:Key="InlineConverter" />
then you can invoke the converter from your TextBlock as follows:
<TextBlock Text="{Binding MyPath}" TextWrapping="Wrap">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmdex:EventToCommand Command="{Binding Source={StaticResource InlineConverter}, Path=ConvertTextToInlinesCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
Apologies if you're not using MVVMLight. If you're not, I'll leave the translation as an exercise for the reader. :)
You can't bind to Text and substitute with Runs because Text is of type String. Instead, you'd need to bind Inlines and provide a converter that parses the text (using your regex, for example) and produces the appropriate Inlines:
<TextBlock Inlines="{Binding XPath=/statuses/status[2]/text, Converter={StaticResource InlineConverter}}"/>

Categories