I am working on a WPF app. In this app, I have some XAML segments. I need to display the XAML segments in a TextBlock. In my XAML, I have the following line:
<TextBlock Text="{Binding Path=XamlSegment, Converter={StaticResource XamlToTextConverter}}" />
The XamlSegment property will have a value like "-0.275*x2". In an attempt to render this XAML in my UI so that the Superscript shows, I'm using the XamlToTextConverter, which is defined as follows:
namespace MyApp.Converters
{
public class XamlToTextConverter : IValueConverter
{
private static readonly Regex Regex = new Regex("(<.*?)>(.*)(</.*?>)", RegexOptions.Compiled);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// value looks like this: -0.275*x<Run Typography.Variants="Superscript">2</Run>
var xamlText = value as string;
if (xamlText != null)
{
try
{
xamlText = "<TextBlock>" + xamlText + "</TextBlock>";
var xamlTextWithNamespace = Regex.Replace(xamlText, "$1 xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">$2$3");
return XamlReader.Parse(xamlTextWithNamespace);
}
catch (Exception)
{
return value;
}
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
When this converter gets ran, my UI shows "System.Windows.Controls.TextBlock" instead of the rendered XAML. Yet, I don't know why. How do I get my XamlSegment to render in my UI?
Thanks
The Text property of the TextBlock will be set to a TextBlock object according to your XamlToTextConverter. Since the Text property should be type of string, it doesn't know how to show a TextBlock as string. So the default way to get thing done is to use the ToString method on TextBlock to fill the Text property, which makes the value of Text as "System.Windows.Controls.TextBlock".
It seems that you would like to dynamically render the xaml. You could reference this link(Loading XAML XML through runtime?) for a solution.
Related
I Have a Textblock in a grid column which have different values like 2,4,1,0,3 etc.
The values shows the quantity of students who belong to a play group activity as Cricket,BaseBall,Chess, BasketBall,Carrom etc.
On Mouse Over a ToolTip is shown.This Tooltip conatins The name of Student who will play in the Specific Group
PlayGroup.xaml File
<TextBlock TextAlignment="Center" VerticalAlignment="Center" Text="{Binding Path=RowData.Row.PlayGroup}" ToolTipService.ToolTip="{Binding Converter={StaticResource TooltipView}}"/>
<UserControl.Resources>
<innercontrols:ListToStringConverter x:Key="TooltipView"/>
</UserControl.Resources>
PlayGroup.CS File
public class ListToStringConverter : IValueConverter //List To String Converter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
List<string> lst = new List<string>();
string combindedString = "";
try
{
lst.Clear();
lst.Add("Cricket");
lst.Add("BaseBall");
lst.Add("Chess");
combindedString = string.Join("\n", lst.ToArray());
return combindedString;
}
catch (Exception ex)
{
} return combindedString;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value; // throw new NotImplementedException();
}
}
How can I bind Dynamic List as Tooltip based on the number of Students?
Should I use String Builder or List or Observable Collection?
In the above I have given a list of 3 students ,but we require to show dynamic data as list .
There must be a property in your model where "PlayGroup" is defined. Bind that property with the tooltip of the textblock. Once you do that the "value" parameter in your ListToStringConverter will have the list of names you passed to the converter. Use it to create the combindedString.
I know that you can limit the input characters of TextBox from user by setting MaxLength property.
Is there a similar way to limit the number of characters shown in Text when the Text is updated with Binding? For example, when it is updated from Binding just show the first 5 characters and leave the rest?
Update:
Thanks for all the info, I got inspired by your recommendation and in the end did it with a converter. Here is how I did it, if someone wants to use it later.
public class StringLimiter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = value.ToString();
if (val.Length < 5)
return val;
else
return val.Substring(0, 5);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = value.ToString();
if (val.Length < 5)
return val;
else
return val.Substring(0, 5);
}
}
This should work:
Xaml:
<TextBox Text="{Binding TextToDisplay}" />
Code:
private const int maxLength = 5;
private string _textToDisplay = "Hello SO";
public string TextToDisplay
{
get
{
if(_textToDisplay.Length > maxLength)
{
return _textToDisplay.Substring(0, maxLength);
}
return _textToDisplay;
}
set
{
_textToDisplay = value;
RaiseProperyChanged();
}
}
I hope to understand you right. You could create a new Property in the ViewModel that returns only the first 5 chars of the text and set your binding to that property.
You might need to call PropertyChanged for the new Property when the text changes.
A simple but very flexible way of doing it would be to introduce a projected property in your Viewmodel that returns the first 5 characters of the original property and then bind your control to this property. Since you're only showing part of the property value, I assume that you don't want to write to this property from that TextBox. So make you projected property read-only too.
I have a TextBlock as follow:
<TextBlock Text="You don't have any more items." Visibility="{binding}"
and in code behind I defined a Stack called items as follow:
private Stack<Item> _items;
How do I bind the text visibility in xaml to visible when _item.Any is false?
There are several steps to achieving what you want to do and they are all described here
You need to create a value converter similar to this;
public class EmptyCollectionToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var collection = (Stack<int>) value;
return collection.Any() ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you need to add a reference to is in your resource dictionary in your xaml like this;
<views:EmptyCollectionToVisibilityConverter x:Key="EmptyCollectionToVisibilityConverter"/>
Finally bind your property in your view model to the visibility of your control and give the binding the converter like this;
Visibility="{Binding Items, Converter={StaticResource EmptyCollectionToVisibilityConverter}}"
Your property will probably need to be an observableCollection (which will mean changing the value converter example I gave you slightly.
I'd probably go with:
private Stack<Item> _items;
// bind to this property using converter
public bool IsVisible => !(_items?.Any(...) ?? false);
You shouldn't expose your _stack directly, but e.g. use methods to do something (because you need to rise notification every time you push/pop an item):
public void PushItem(Item item)
{
_items.Push(item);
OnPropertyChanged(nameof(IsVisible)); // implement INotifyPropertyChanged
}
I am just learning Datagrids and had a question I could not find a clear answer to.
How would I be able to manipulate a bound string to replace everything before the last / and add then a different prefix.
This will be to show an image in a Datagrid.
For example what is bound to img variable is
img: "/img_banner/testBanner.jpg"
What finally needs to be output is this:
http://www.testsite.com/img_thumnail/testBanner.jpg
So far, I have found information about adding text to a bound string but I would like to remove part of the String.
Here is what I got so far:
<Image Source="{Binding img, StringFormat=http://www.testsite.com/img_thumnail{0}}" Height="40"/>
Is there any way to easily trim everything before the last / ?
You can use an IValueConverter:
public class MyUrlConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return null;
}
var urlString = value as string;
//now do whatever you want to do with the string
//then return it
return urlString;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
then add it to your resources
<Window.Resources>
<local:MyUrlConverter x:Key="conv"></local:MyUrlConverter>
</Window.Resources>
and use it as:
<Image Source="{Binding img,Converter={StaticResource ResourceKey=conv}}"></Image>
note that if the logic dependant on your view model then you better do your thing in the getter or the setter of your img property
Tearing my hair out here! I have this type-converter:
class CouponBarcodeToVisibilityConverterColumn : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (DesignerProperties.IsInDesignMode)
{
if ((string)parameter == "123456")
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
if (value == null)
{
return Visibility.Visible;
}
var barcodesWanted = ((string)parameter).Split(System.Convert.ToChar("_"));
var actualBarcode = (string)value;
return barcodesWanted.Any(barcodeWanted => barcodeWanted == actualBarcode) ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I have a UserControl with the following Resources section:
<UserControl.Resources>
<converters:CouponBarcodeToVisibilityConverterColumn x:Key="CouponBarcodeToVisibilityConverter1"/>
</UserControl.Resources>
I have a model called Bet, it looks like this:
public class Bet : INotifyPropertyChanged
{
//Lots of other stuff
private string _barcode;
public string Barcode
{
get { return _barcode; }
set
{
if (value == _barcode) return;
_barcode = value;
OnPropertyChanged("Barcode");
}
}
//Lots of other stuff
}
In the ViewModel which is the DataContext of my user control I have an Observable Collection of Bet. Back to my user control, I have a stack panel, the data context of which is the aforementioned Observable Collection.
Inside the Stack Panel I have a DataGrid, the ItemsSource property is simply {Binding}, deferring the binding up the tree as it were.
Inside my DataGrid I have this column:
<DataGridCheckBoxColumn x:Name="IsEwColumn" Binding="{Binding Wagers[0].IsEw,UpdateSourceTrigger=PropertyChanged}" Header="Each Way" Visibility="{Binding Path=Barcode, Converter={StaticResource CouponBarcodeToVisibilityConverter1}, ConverterParameter=123456}" Width="Auto"/>
The other element of the binding works perfectly (the checkbox is ticked whenever it is supposed to be) but my type converter is not. The breakpoint doesn't even get hit. The Barcode property inside Bet is definitely equal to 123456.
What have I missed?
What you have here is a list of bets for the items source of the data grid.
If you think about it
Bet1 could evaluate to visible when passed via type converter.
Bet2 could evaluate to visible when passed via type converter.
Bet3 could evaluate to collapsed when passed via type converter.
How would the datacolumn be both visible and collapsed at the same time.
You can't bind to visibility like that, unless you had an overall variable on the list or something that it could bind to.