Change Binding value in XAML - c#

I need to make some complex binding in XAML. I have a DependencyProperty typeof(double); let's name it SomeProperty. Somewhere in XAML code of my control, I need to use the whole SomeProperty value, somewhere only a half, somewhere SomeProperty/3, and so on.
How can I do something like:
<SomeControl Value="{Binding ElementName=MyControl, Path=SomeProperty} / 3"/>
:)
Looking forward.

Use a division ValueConverter:
public class DivisionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int divideBy = int.Parse(parameter as string);
double input = (double)value;
return input / divideBy;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
<!-- Created as resource -->
<local:DivisionConverter x:Key="DivisionConverter"/>
<!-- Usage Example -->
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=1}"/>
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=2}"/>
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=3}"/>

Related

How to join a List and bind it with a TextBlock in a GridView Block

I want to join a list and bind them within a TextBlock in a GridView (or ListView) block.
Let me draw a picture to explain the scenario.
C#
I have a list of StudentInfo which contains Name (string), ID (int) and Courses (List<string)
XAML
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:StudentInfo">
<StackPanel>
<TextBlock Text="{x:Bind StudentName}" Margin="1"/>
<TextBlock Text="{x:Bind ID}" Margin="1"/>
<!--In the following textblock, I want to show something like this
"Taken Courses Are - PHY, CHM, MAT"-->
<TextBlock Text="{x:Bind Courses}" Margin="1"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
In the last TextBlock I want to join all the courses a student have taken and show them with a hard coaded text -
"Taken Courses Are - ".
How can I do that?
you can simply use a IValueConverter to Bind list
<TextBlock Text="{x:Bind Courses,Converter={StaticResource ListToStringConverter}}" Margin="1"/>
Here the Converter
public class ListToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, string language)
{
return String.Join(", ", ((List<string>)value).ToArray());
}
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Edit
Add ListToStringConverter to your resources
<Page.Resources>
<local:ListToStringConverter x:Name="ListToStringConverter" ></local:ListToStringConverter>
</Page.Resources>
Write a converter class to covert your list to a comma separated string.
XAML code
<TextBlock Text="{Binding Path=Courses,Converter={StaticResource CourseToStringConverter}}" Margin="1"/>
CourseToStringConverter
[ValueConversion(typeof(List<string>), typeof(string))]
public class CourseToStringConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(string))
throw new InvalidOperationException("The target must be a String");
return "Taken Courses Are - " + String.Join(", ", ((List<string>)value).ToArray());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Change wpf style from viewmodel

I have a DataTemplate:
<DataTemplate
DataType="{x:Type local:ConnectionViewModel}"
>
<!-- The connection is represented by a curved arrow. -->
<ca:CurvedArrow
StrokeThickness="2"
Points="{Binding Points}"
Fill="{StaticResource connectionBrush}"
Stroke="{StaticResource connectionBrush}"
/>
</DataTemplate>
This represent all the connector i have in my view.
What I want to do is to set a different fill and stroke for specific specific connectors from the viewmodel.
How can I achive that?
You should be avoiding any UI objects in viewmodel.
For the mentioned use case, you can make use of Converters and continue to only have business object level information in your viewmodel.
For instance, you Connection class can hold a property of enum : ConnectorType {Arrow,Circle,Rectangle} and then you can write a Converter which converts enum type to desired color brush. Sample code below:
//Inside Resources. local=namespace where you have this converter
<local:ConnectorType2BrushConverter x:Key="ConnectorType2BrushConverter" />
....
<ca:CurvedArrow
StrokeThickness="2"
Points="{Binding Points}"
Fill="{Binding Path=ConnectorType, Converter={StaticResource ResourceKey=ConnectorType2BrushConverter}"
/>
....
public class ConnectorType2BrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var connectorType = (ConnectorType)value;
if (connectorType == ConnectorType.Arrow)
{
return new SolidColorBrush(Color.FromRgb(1, 1, 1));
}
else .....
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Windows Phone 8 bind to string resource with format

My localized resource string, named TextResource has the value: Text: {0}. Where {0} is the placeholder for String.Format.
My user control has a DependecyProperty called Count.
I would like to bind Count to the text of a text box but also apply the localized string. So that the content of the text block is Text: 5 (assuming the value of Count is 5)
I managed to figure out how to bind the localized string
<TextBlock Text="{Binding Path=LocalizedResources.TextResource, Source={StaticResource LocalizedStrings}}" />
or the property value
<TextBlock Text="{Binding Path=Count}" />
but not both simultaneous.
How can I do that in XAML?
PS: One option would be to add two text blocks instead of one but I am not sure if that is a good practice.
You have three options here.
First option: Modify your view model to expose your formatted string and bind to that.
public string CountFormatted {
get {
return String.Format(AppResources.TextResource, Count);
}
}
<TextBlock Text="{Binding Path=CountFormatted}" />
Second option: Make a converter MyCountConverter
public class MyCountConverter: IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value == null)
return value;
return String.Format(culture, AppResources.TextResource, value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
<phone:PhoneApplicationPage.Resources>
<local:MyCountConverter x:Key="MyCountConverter"/>
</phone:PhoneApplicationPage.Resources>
...
<TextBlock Text="{Binding Count, Converter={StaticResource MyCountConverter}}"/>
Third option: Use bind-able converter parameter so that you can make a general StringFormat converter where you can actually bind the converter parameter. This is not supported out of the box in windows phone but is still doable. Check this link on how it can be done.
However, unless you are using resources to support multiple languages then it's much easier to just pass your format as a plain string to a converter.
<TextBlock Text="{Binding Count,
Converter={StaticResource StringFormatConverter},
ConverterParameter='Text: {0}'}" />
You'll have to make a StringFormatConverter converter that uses the parameter in this case.
Edit:
Regarding third option, you can use the IMultiValueConverter in the link above to achieve what you want. You can add the following converter:
public class StringFormatConverter: IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
var param = values[0].ToString();
var format = values[1].ToString();
return String.Format(culture, format, param);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
<TextBlock Text="{Binding ElementName=MultiBinder, Path=Output}" />
<binding:MultiBinding x:Name="MultiBinder" Converter="{StaticResource StringFormatConverter}"
NumberOfInputs="2"
Input1="{Binding Path=Count, Mode=TwoWay}"
Input2="{Binding Path=LocalizedResources.TextResource, Source={StaticResource LocalizedStrings}}" />
I don't know if it's worth the effort though.

DataTemplate binding grid background through a converter

I have a problem for a while with a data binding that changes the color of a grid and somehow it doesn't work.
Iv'e put a break point in the converter and the application hit it, but still the background color of the grid doesn't change and it stays as there is no background color defined...
here is my code:
<ListView ItemsSource="{Binding ResultsUserControls}"
Background="{x:Null}"
BorderBrush="{x:Null}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="200"
Height="70"
Background="{Binding CurrentResult,Converter={StaticResource crawlerTypeToResultColorConverter}}">
<Label Content="{Binding .CurrentResult.SourceUrl}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and the converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Brushes.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
I think this should be
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return new SolidColorBrush(Colors.Red);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
I've tinkered with your code, and what you have should work. As an experiment, delete CurrentResult from your binding for Background:
<Grid Width="200" Height="70" Background="{Binding Converter={StaticResource crawlerTypeToResultColorConverter}}">
I suspect you will see your red background now. I noticed that if the XAML parser can't find the property that you're binding to (because it's misspelled or just doesn't exist) it won't do the conversion. I would guess that the XAML parser isn't able to find CurrentResult on your items.

Make converter for columnSpan

I would like to dynamic do the columnSpan on the userControl. I created the converter class, but it didn’t work. Would you show me how to do it correctly? Thanks.
The code on my UserControl:
<TextBlock x:Name="txtSumary" Grid.Row="0" Grid.Column="1" Text="{Binding summary}"
TextWrapping="Wrap" Style="{StaticResource PhoneTextAccentStyle}" Grid.ColumnSpan="{Binding isSpan, Converter={StaticResource ColumSpanConverter}}" />
It is reference on the UserControl.Resources
<local:VisibilityConverter x:Key="ColumSpanConverter"/>
There is the Converter Class:
public class ColumSpanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isSpan = (bool)value;
return isSpan ? 2 : 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
The converter is referencing the wrong converter:
<local:VisibilityConverter x:Key="ColumSpanConverter"/>
Should be:
<local:ColumSpanConverter x:Key="ColumSpanConverter" />

Categories