Convert int textbox input to negative in xaml? - c#

I have a textbox where the user enters in a number that is to be used as the angle to rotate an image. Is there a way to convert that number in xaml to negative? So if the user enters 50, I want the image to rotate -50 degrees instead of +50. I'd rather not do it in the code-behind. Code for it is below:
<TextBox x:Name="testing" />
<Image Source="aaaa.png" x:Name="thisimage" >
<Image.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding Path=Text , ElementName=testing, UpdateSourceTrigger=PropertyChanged}" />
</Image.LayoutTransform>
</Image>

This would be a pure XAML solution:
<Image.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<RotateTransform CenterX="0.5" CenterY="0.5"
Angle="{Binding Path=Text, ElementName=testing,
UpdateSourceTrigger=PropertyChanged}" />
<ScaleTransform ScaleX="-1"/>
</TransformGroup>
</Image.LayoutTransform>
I would still recommend using a binding converter.

Try following code.
Firstly create implementing IValueConverter:
public class AngleConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var angle = (int)value;
if (angle != null)
{
return -angle;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
XAML:
<TextBox x:Name="testing" />
<Image Source="aaaa.png" x:Name="thisimage" >
<Image.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding Path=Text , ElementName=testing, Converter={StaticResource angleConverter} UpdateSourceTrigger=PropertyChanged}" />
</Image.LayoutTransform>
Add reference to your converter:
xmlns:cr="using:[project].Converters"
Don't forget add to resource:
<UserControl.Resources>
<cr:AngleConverter x:Key="angleConverter"/>
</UserControl.Resources>

Related

WPF Position TextBlock/Label on the Line center

Im trying to represent weighted graph with MVVM inside canvas
so im representing graphs vertices and edges as observable collections and putting them into canvas ItemsControl. But I cant find any reasonable way to position text that represents weight on the center of line(graphs edge)
my canvas xaml:
<Canvas Background="Linen" ClipToBounds="True"
Grid.Row="0" Grid.Column="0">
<ItemsControl ItemsSource="{Binding EdgeItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line Stroke="Black" StrokeThickness="4"
X1="{Binding V1.X}" Y1="{Binding V1.Y}"
X2="{Binding V2.X}" Y2="{Binding V2.Y}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
What i want to get
Add to your EdgeItem class (or whatever's in your EdgeItems collection).
// When V1 or V2 changes, raise PropertyChanged("Margin")
public Thickness Margin => new Thickness(Left, Top, 0, 0);
public double Left => Math.Min(V1.X, V2.X);
public double Top => Math.Min(V1.Y, V2.Y);
I'm assuming EdgeItem has a Weight property -- if not, Weight is a stand-in for whatever property you want to display in the center of the line. I would have thought Canvas.Left and Canvas.Top would work, but for me they don't in this case.
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Line
Stroke="Black"
StrokeThickness="4"
X1="{Binding V1.X}"
Y1="{Binding V1.Y}"
X2="{Binding V2.X}"
Y2="{Binding V2.Y}"
/>
<Label
Background="#ccffffff"
Content="{Binding Weight}"
Margin="{Binding Margin}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Second Method
Alternatively, don't add the Margin, Left, and Top properties to EdgeItem, and generate the margin Thickness with a value converter instead. I'm not crazy about having those properties on EdgeItem, but then again on the other hand, a value converter on {Binding} is a problem with raising PropertyChanged, if you happen to alter V1 or V2 at runtime. The solution to that would be to make it a multi value converter and bind V1 and V2 separately with a multi binding. I just got lazy about writing that XAML.
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Line
Stroke="Black"
StrokeThickness="4"
X1="{Binding V1.X}"
Y1="{Binding V1.Y}"
X2="{Binding V2.X}"
Y2="{Binding V2.Y}"
/>
<Label
Background="#ccffffff"
Content="{Binding Weight}"
Margin="{Binding Converter={local:EdgeItemMargin}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Converter:
public class EdgeItemMargin : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var edge = (EdgeItem)value;
return new Thickness(
Math.Min(edge.V1.X, edge.V2.X),
Math.Min(edge.V1.Y, edge.V2.Y),
0, 0);
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}

how to show Path-elements (icons) in WPF combobox?

I can only get the paths visible on button-elements:
<ComboBox
Margin="0 0 0 0"
ItemsSource="{Binding Path=SearchTypes}"
SelectedItem="{Binding Path=SearchType}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Button>
<Path
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{Binding Converter={StaticResource searchtypetoimagepathconverter}}" />
</Button>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
EDIT:
My converter looks like this:
public class SearchTypeToImagePathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if ((SearchType)value == SearchType.Customers)
return App.Current.Resources["Geometry.User"];
else
return App.Current.Resources["Geometry.Share"];
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
EDIT 2
Following xaml also works:
<ComboBox Grid.Column="0">
<ComboBoxItem Name="share">
<Path Stretch="Uniform"
Margin="0 0 0 0"
VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}"
Data="{StaticResource Geometry.Share}" />
</ComboBoxItem>
<ComboBoxItem Name="user">
<Path Stretch="Uniform"
Margin="0 0 0 0"
VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}"
Data="{StaticResource Geometry.User}" />
</ComboBoxItem>
</ComboBox>
So the result of converter is returning StreamGeometry that shows only in Path.Data inside a Button. I have no idea what it means.
What would be the correct parent for path-element?
A popular way to use xaml icons is as shown below. So to answer you question the parent of Path could be a VisualBrush.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Path x:Key="Repeat" Data="M33.6412,13.3342 C34.1892,13.3157 34.7319,13.5192 35.13,13.9098 L35.481,14.2528 C35.481,14.2528 35.582,14.3529 35.7709,14.5368 C35.9579,14.7128 36.23,15.0029 36.5609,15.4108 C37.1629,16.2189 37.9739,17.4969 38.4219,19.3309 C38.8089,21.1459 38.7448,23.518 37.6809,25.8689 C37.1779,27.055 36.3619,28.151 35.374,29.135 C34.385,30.122 33.173,30.941 31.8641,31.526 C30.5591,32.123 29.1672,32.514 27.7932,32.7191 C26.6272,32.835 25.4812,32.949 24.3702,33.058 C22.3023,33.225 20.3734,33.306 18.7194,33.3311 C18.2234,33.337 17.7625,33.3311 17.3184,33.322 L17.3184,37.4851 C17.3184,37.9501 17.0455,38.3731 16.6175,38.5631 C16.1905,38.7541 15.6875,38.6781 15.3385,38.3651 C11.6946,35.1181 8.44271,30.534 8.10575,29.838 C7.94676,29.513 7.94773,29.134 8.10672,28.81 C8.44674,28.111 11.7056,23.539 15.3385,20.3029 C15.5615,20.1049 15.8435,20.0009 16.1305,20.0009 C16.2945,20.0009 16.4615,20.0329 16.6175,20.1029 C17.0455,20.2929 17.3184,20.7169 17.3184,21.1819 L17.3184,25.4649 L18.7194,25.4649 L24.3702,25.4649 L25.9463,25.4649 L26.7262,25.4649 L27.2972,25.443 C28.0551,25.394 28.7772,25.2489 29.4311,25.015 C30.7441,24.555 31.7651,23.706 32.385,22.7049 C33.01,21.7019 33.2271,20.5769 33.1671,19.6069 C33.113,18.6339 32.807,17.8179 32.546,17.2659 C32.494,17.1589 32.447,17.0689 32.4051,16.9849 C32.3871,16.9309 32.2491,16.7249 32.1991,16.6379 C32.065,16.4209 31.995,16.3049 31.995,16.3049 C31.4251,15.3779 31.7301,14.1728 32.679,13.6148 C32.9817,13.4363 33.3124,13.3453 33.6412,13.3342 z M22.5228,8.9E-05 C22.8046,0.003539 23.0829,0.107522 23.301,0.302508 C26.9451,3.5505 30.1972,8.13145 30.5352,8.83045 C30.6932,9.15446 30.6922,9.53443 30.5332,9.85644 C30.1932,10.5554 26.9351,15.1274 23.301,18.3644 C23.079,18.5624 22.796,18.6674 22.509,18.6674 C22.345,18.6674 22.179,18.6324 22.024,18.5634 C21.5949,18.3754 21.32,17.9504 21.32,17.4844 L21.32,13.2024 L19.9199,13.2024 L14.2688,13.2024 L12.6927,13.2024 L11.9117,13.2034 L11.3407,13.2234 C10.5837,13.2744 9.86266,13.4184 9.20768,13.6524 C7.89466,14.1114 6.8726,14.9604 6.25461,15.9604 C5.62861,16.9634 5.41059,18.0914 5.47059,19.0594 C5.52461,20.0343 5.83058,20.8484 6.09158,21.4004 C6.14462,21.5073 6.19162,21.5993 6.23459,21.6823 C6.25058,21.7353 6.3906,21.9433 6.43961,22.0283 C6.57261,22.2464 6.64359,22.3623 6.64359,22.3623 C7.21465,23.2883 6.90764,24.4953 5.95962,25.0523 C5.15259,25.5273 4.14457,25.3833 3.50851,24.7583 L3.15651,24.4143 C3.15651,24.4143 3.05653,24.3153 2.8675,24.1303 C2.67951,23.9523 2.40753,23.6643 2.07848,23.2563 C1.4755,22.4473 0.664446,21.1703 0.216437,19.3354 C-0.169559,17.5204 -0.105531,15.1484 0.956445,12.7964 C1.45951,11.6114 2.27648,10.5154 3.26454,9.53144 C4.25456,8.54444 5.46461,7.72646 6.77561,7.13946 C8.07966,6.54446 9.47166,6.15448 10.8467,5.94647 C12.0118,5.83145 13.1588,5.71946 14.2688,5.61048 C16.3368,5.44346 18.2669,5.35947 19.9199,5.33549 C20.416,5.33146 20.877,5.33549 21.32,5.34348 L21.32,1.18251 C21.32,0.716507 21.5949,0.292529 22.024,0.104512 C22.1833,0.032141 22.3537,-0.001981 22.5228,8.9E-05 z" Fill="Black" Stretch="Uniform" UseLayoutRounding="False"/>
<Path x:Key="Tablet" Data="M9.3486,21.052 C12.3243,21.076 14.586,23.011 14.586,26.307 L11.8403,26.307 C10.4715,26.307 9.3486,25.232 9.3486,23.859 C9.3486,23.859 9.3226,21.276 9.3486,21.052 z M35.334,15.289 C33.91,15.289 32.752,16.442 32.752,17.866 C32.752,19.292 33.91,20.448 35.334,20.448 C36.755,20.448 37.915,19.292 37.915,17.866 C37.915,16.442 36.755,15.289 35.334,15.289 z M9.51959,15.129 C11.4734,15.1341 14.5284,15.6521 17.266,18.4421 C19.2481,20.458 20.4901,23.01 20.4981,26.307 L17.4221,26.307 C17.415,24.327 16.524,22.117 15.091,20.657 C12.894,18.422 10.628,18.245 9.334,18.258 L9.334,15.1301 C9.39468,15.1292 9.45657,15.1289 9.51959,15.129 z M9.33399,9.19698 C11.922,9.19698 17.076,9.73195 21.519,14.2597 C24.555,17.3515 26.451,21.6913 26.47,26.306 L23.246,26.306 C23.227,22.3512 21.683,19.0074 19.198,16.4726 C15.56,12.7758 11.276,12.3308 9.33399,12.3308 z M20.055,5.01599 C15.143,5.01599 10.23,5.297 5.33398,5.75299 L5.33398,29.984 C10.23,30.44 15.143,30.718 20.055,30.718 C23.594,30.718 27.134,30.544 30.667,30.309 L30.667,5.42599 C27.134,5.19 23.594,5.01599 20.055,5.01599 z M20,0 C25.076,0 30.476,0.242004 35.531,0.718018 C38.066,0.958008 40,3.086 40,5.63 L40,30.104 C40,32.648 38.066,34.776 35.531,35.016 C30.476,35.494 25.076,35.737 20,35.737 C14.924,35.737 9.522,35.494 4.47,35.016 C1.935,34.776 0,32.648 0,30.104 L0,5.63 C0,3.086 1.935,0.958008 4.47,0.718018 C9.522,0.242004 14.924,0 20,0 z" Fill="Black" Stretch="Uniform" UseLayoutRounding="False"/>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle>
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource Repeat}" />
</Rectangle.Fill>
</Rectangle>
<Rectangle Fill="Black" Grid.Column="1">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource Tablet}" />
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
</Page>
This demonstrates two ways. Use as an opacity mask or use as fill. This could be applied to any control for creating icon effect.
Put to ur example
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Path x:Key="Repeat" Data="M33.6412,13.3342 C34.1892,13.3157 34.7319,13.5192 35.13,13.9098 L35.481,14.2528 C35.481,14.2528 35.582,14.3529 35.7709,14.5368 C35.9579,14.7128 36.23,15.0029 36.5609,15.4108 C37.1629,16.2189 37.9739,17.4969 38.4219,19.3309 C38.8089,21.1459 38.7448,23.518 37.6809,25.8689 C37.1779,27.055 36.3619,28.151 35.374,29.135 C34.385,30.122 33.173,30.941 31.8641,31.526 C30.5591,32.123 29.1672,32.514 27.7932,32.7191 C26.6272,32.835 25.4812,32.949 24.3702,33.058 C22.3023,33.225 20.3734,33.306 18.7194,33.3311 C18.2234,33.337 17.7625,33.3311 17.3184,33.322 L17.3184,37.4851 C17.3184,37.9501 17.0455,38.3731 16.6175,38.5631 C16.1905,38.7541 15.6875,38.6781 15.3385,38.3651 C11.6946,35.1181 8.44271,30.534 8.10575,29.838 C7.94676,29.513 7.94773,29.134 8.10672,28.81 C8.44674,28.111 11.7056,23.539 15.3385,20.3029 C15.5615,20.1049 15.8435,20.0009 16.1305,20.0009 C16.2945,20.0009 16.4615,20.0329 16.6175,20.1029 C17.0455,20.2929 17.3184,20.7169 17.3184,21.1819 L17.3184,25.4649 L18.7194,25.4649 L24.3702,25.4649 L25.9463,25.4649 L26.7262,25.4649 L27.2972,25.443 C28.0551,25.394 28.7772,25.2489 29.4311,25.015 C30.7441,24.555 31.7651,23.706 32.385,22.7049 C33.01,21.7019 33.2271,20.5769 33.1671,19.6069 C33.113,18.6339 32.807,17.8179 32.546,17.2659 C32.494,17.1589 32.447,17.0689 32.4051,16.9849 C32.3871,16.9309 32.2491,16.7249 32.1991,16.6379 C32.065,16.4209 31.995,16.3049 31.995,16.3049 C31.4251,15.3779 31.7301,14.1728 32.679,13.6148 C32.9817,13.4363 33.3124,13.3453 33.6412,13.3342 z M22.5228,8.9E-05 C22.8046,0.003539 23.0829,0.107522 23.301,0.302508 C26.9451,3.5505 30.1972,8.13145 30.5352,8.83045 C30.6932,9.15446 30.6922,9.53443 30.5332,9.85644 C30.1932,10.5554 26.9351,15.1274 23.301,18.3644 C23.079,18.5624 22.796,18.6674 22.509,18.6674 C22.345,18.6674 22.179,18.6324 22.024,18.5634 C21.5949,18.3754 21.32,17.9504 21.32,17.4844 L21.32,13.2024 L19.9199,13.2024 L14.2688,13.2024 L12.6927,13.2024 L11.9117,13.2034 L11.3407,13.2234 C10.5837,13.2744 9.86266,13.4184 9.20768,13.6524 C7.89466,14.1114 6.8726,14.9604 6.25461,15.9604 C5.62861,16.9634 5.41059,18.0914 5.47059,19.0594 C5.52461,20.0343 5.83058,20.8484 6.09158,21.4004 C6.14462,21.5073 6.19162,21.5993 6.23459,21.6823 C6.25058,21.7353 6.3906,21.9433 6.43961,22.0283 C6.57261,22.2464 6.64359,22.3623 6.64359,22.3623 C7.21465,23.2883 6.90764,24.4953 5.95962,25.0523 C5.15259,25.5273 4.14457,25.3833 3.50851,24.7583 L3.15651,24.4143 C3.15651,24.4143 3.05653,24.3153 2.8675,24.1303 C2.67951,23.9523 2.40753,23.6643 2.07848,23.2563 C1.4755,22.4473 0.664446,21.1703 0.216437,19.3354 C-0.169559,17.5204 -0.105531,15.1484 0.956445,12.7964 C1.45951,11.6114 2.27648,10.5154 3.26454,9.53144 C4.25456,8.54444 5.46461,7.72646 6.77561,7.13946 C8.07966,6.54446 9.47166,6.15448 10.8467,5.94647 C12.0118,5.83145 13.1588,5.71946 14.2688,5.61048 C16.3368,5.44346 18.2669,5.35947 19.9199,5.33549 C20.416,5.33146 20.877,5.33549 21.32,5.34348 L21.32,1.18251 C21.32,0.716507 21.5949,0.292529 22.024,0.104512 C22.1833,0.032141 22.3537,-0.001981 22.5228,8.9E-05 z" Fill="Black" Stretch="Uniform" UseLayoutRounding="False"/>
<Path x:Key="Tablet" Data="M9.3486,21.052 C12.3243,21.076 14.586,23.011 14.586,26.307 L11.8403,26.307 C10.4715,26.307 9.3486,25.232 9.3486,23.859 C9.3486,23.859 9.3226,21.276 9.3486,21.052 z M35.334,15.289 C33.91,15.289 32.752,16.442 32.752,17.866 C32.752,19.292 33.91,20.448 35.334,20.448 C36.755,20.448 37.915,19.292 37.915,17.866 C37.915,16.442 36.755,15.289 35.334,15.289 z M9.51959,15.129 C11.4734,15.1341 14.5284,15.6521 17.266,18.4421 C19.2481,20.458 20.4901,23.01 20.4981,26.307 L17.4221,26.307 C17.415,24.327 16.524,22.117 15.091,20.657 C12.894,18.422 10.628,18.245 9.334,18.258 L9.334,15.1301 C9.39468,15.1292 9.45657,15.1289 9.51959,15.129 z M9.33399,9.19698 C11.922,9.19698 17.076,9.73195 21.519,14.2597 C24.555,17.3515 26.451,21.6913 26.47,26.306 L23.246,26.306 C23.227,22.3512 21.683,19.0074 19.198,16.4726 C15.56,12.7758 11.276,12.3308 9.33399,12.3308 z M20.055,5.01599 C15.143,5.01599 10.23,5.297 5.33398,5.75299 L5.33398,29.984 C10.23,30.44 15.143,30.718 20.055,30.718 C23.594,30.718 27.134,30.544 30.667,30.309 L30.667,5.42599 C27.134,5.19 23.594,5.01599 20.055,5.01599 z M20,0 C25.076,0 30.476,0.242004 35.531,0.718018 C38.066,0.958008 40,3.086 40,5.63 L40,30.104 C40,32.648 38.066,34.776 35.531,35.016 C30.476,35.494 25.076,35.737 20,35.737 C14.924,35.737 9.522,35.494 4.47,35.016 C1.935,34.776 0,32.648 0,30.104 L0,5.63 C0,3.086 1.935,0.958008 4.47,0.718018 C9.522,0.242004 14.924,0 20,0 z" Fill="Black" Stretch="Uniform" UseLayoutRounding="False"/>
</Page.Resources>
<Grid>
<ComboBox Grid.Column="0" Height="40" Width="200">
<ComboBoxItem Name="share">
<Rectangle Height="40" Width="40">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource Repeat}" />
</Rectangle.Fill>
</Rectangle>
</ComboBoxItem>
<ComboBoxItem Name="user">
<Rectangle Fill="Black" Height="40" Width="40">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource Tablet}" />
</Rectangle.OpacityMask>
</Rectangle>
</ComboBoxItem>
</ComboBox>
</Grid>
</Page>
This is your exact use case. Do mark it as an answer if this helps for benefit of others.
EDIT you should add to Path element : Stroke="Red" and remove the button.
I agree with the comments saying that a parent shouldn't be necessary for the Path object, but to solve your problem, this might help: a Button is a ContentControl with added functionality. You don't need the added functionality, so try wrapping the Path in a ContentControl.
Button has default style and so it gives Stroke and Fill to make the StreamGeometry assigned in Button.Path.Data visible.
However ContentControl or plain Path element gets somehow invisible values for these so they are not shown.
This is bad answer, but I edited the question so many times already that I put answer here. Please make better answer with decent references and data and I accept it.

Array Binding simple example doesn't work

I'm very new to xaml and I'm trying to understand the Binding issue. I have a problem with the Array Binding. I created this very simple example: I have a stack panel with three images. Each image has a RotationTransform. Each Angle is obtained by an array element (the array is a DependencyProperty called Rotations). This is the xaml simple file:
<StackPanel Orientation="Vertical">
<Image Source="/Assets/knife.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding ElementName=pageRoot, Path=Rotations[0], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Image Source="/Assets/fork.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding ElementName=pageRoot, Path=Rotations[1], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Image Source="/Assets/spoon.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding ElementName=pageRoot, Path=Rotations[2], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Button x:Name="actionButton" Content="Try Binding!"
Click="Op_Click"/>
</StackPanel>
And this is my c# class:
public sealed partial class MainPage : Page
{
public static readonly DependencyProperty RotationsProperty = DependencyProperty.Register("Rotations", typeof(double[]), typeof(MainPage),
new PropertyMetadata(new double[3]));
public double[] Rotations
{
get { return (double[])GetValue(RotationsProperty); }
set { SetValue(RotationsProperty, value); }
}
private void Op_Click(object sender, RoutedEventArgs e)
{
Rotations[0] = 180;
Rotations[1] = 130;
Rotations[2] = 350;
}
public MainPage()
{
this.InitializeComponent();
Rotations[0] = 20;
Rotations[1] = 90;
Rotations[2] = 180;
}
}
The binding works only the first time (at startup time). When I click on the button (changing the Rotations array) the binding doesn't work and it is completely ignored from my images.
This is a very simple example, so it's clear that I miss something concerning the Binding issue.
I guess the problem is that you change the value of the array entries, but you don't change the array itself, so 'SetValue' does not get called. You could try to set 'Rotations' to a new array.
this.Rotations = new double[] {180, 130, 350};
Edit: I tested your code with my changes and it worked. Another suggestion would be to write a setter method for the array entries and call 'SetValue' or (like suggested in the comments) use 'INotifyPropertyChanged' instead of a DependencyProperty.
Try the below code:
Xaml:
<StackPanel Orientation="Vertical">
<Image Source="/Assets/knife.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding Rotations[0], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Image Source="/Assets/fork.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding Rotations[1], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Image Source="/Assets/spoon.png" Width="50" Height="100" Stretch="Uniform" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding Rotations[2], Mode=OneWay}"/>
</Image.RenderTransform>
</Image>
<Button x:Name="actionButton" Content="Try Binding!"
Click="Op_Click"/>
</StackPanel>
In the code behind set the DataContext as below :
this.DataContext = this;
Ok, I found a solution using ObservableCollection: the xaml file remains the same, but the c# class changes this way:
public sealed partial class MainPage : Page
{
public static readonly DependencyProperty RotationsProperty =
DependencyProperty.Register("Rotations", typeof(ObservableCollection<double>), typeof(MainPage),
new PropertyMetadata(new ObservableCollection<double>()));
public ObservableCollection<double> Rotations
{
get { return (ObservableCollection<double>)GetValue(RotationsProperty); }
set { SetValue(RotationsProperty, value); }
}
private void Op_Click(object sender, RoutedEventArgs e)
{
Rotations[0] = 180;
Rotations[1] = 180;
Rotations[2] = 320;
}
public MainPage()
{
this.InitializeComponent();
Rotations.Add(90);
Rotations.Add(90);
Rotations.Add(90);
}
}

WPF Binding from strings to Canvas objects in a ResourceDictionary using Converter

I have a ResourceDictionary made up of icons/Canvas objects drawn with Paths. My ViewModel includes a string property (IconName) that contains a string matching one of the entries in the ResourceDictionary. I developed a MultiBinding (IMultiValueConverter) that takes the string, and a FrameworkElement and does a resource lookup, returning the resource matching the name. Before getting to this point, I stubbed my View explicitly with the following:
<Rectangle Width="10" Height="10" Margin="0,0,10,0">
<Rectangle.Fill>
<VisualBrush Stretch="Fill" Visual="{StaticResource defalt_icon}" />
</Rectangle.Fill>
</Rectangle>
This renders correctly. However, when I switch out to the following, nothing is rendered in the Rectangle.
<Rectangle Width="10" Height="10" Margin="0,0,10,0">
<Rectangle.Fill>
<VisualBrush Stretch="Fill">
<VisualBrush.Visual>
<MultiBinding Converter="{StaticResource IconNameConverter}">
<MultiBinding.Bindings>
<Binding RelativeSource="{RelativeSource AncestorType=FrameworkElement}"/>
<Binding Path="IconName"/>
</MultiBinding.Bindings>
</MultiBinding>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
My converter (show below) is being called, and does find the Canvas object and returns it (viewing the object in the debugger I can see that Canvas has a Path child that has the right Data member filled in).
public class IconNameConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
FrameworkElement targetElement = values[0] as FrameworkElement;
string iconName = values[1] as string;
if (iconName == null)
return null;
FrameworkElement newIcon = (FrameworkElement)targetElement.TryFindResource(iconName);
if (newIcon == null)
newIcon = (FrameworkElement)targetElement.TryFindResource("appbar_page_question");
return newIcon;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Any ideas why the canvas isn't showing up?

Vertical Text in Wpf TextBlock

Is it possible to display the text in a TextBlock vertically so that all letters are stacked upon each other (not rotated with LayoutTransform)?
Nobody has yet mentioned the obvious and trivial way to stack the letters of an arbitrary string vertically (without rotating them) using pure XAML:
<ItemsControl
ItemsSource="Text goes here, or you could use a binding to a string" />
This simply lays out the text vertically by recognizing the fact that the string is an IEnumerable and so ItemsControl can treat each character in the string as a separate item. The default panel for ItemsControl is a StackPanel, so the characters are laid out vertically.
Note: For precise control over horizontal positioning, vertical spacing, etc, the ItemContainerStyle and ItemTemplate properties can be set on the ItemsControl.
Just in case anybody still comes across this post... here is a simple 100% xaml solution.
<TabControl TabStripPlacement="Left">
<TabItem Header="Tab 1">
<TabItem.LayoutTransform>
<RotateTransform Angle="-90"></RotateTransform>
</TabItem.LayoutTransform>
<TextBlock> Some Text for tab 1</TextBlock>
</TabItem>
<TabItem Header="Tab 2">
<TabItem.LayoutTransform>
<RotateTransform Angle="-90"></RotateTransform>
</TabItem.LayoutTransform>
<TextBlock> Some Text for tab 2</TextBlock>
</TabItem>
</TabControl>
I don't think there is a straighforward of doing this withought changing the way the system inherently laysout text. The easiest solution would be to change the width of the textblock and supply a few extra properties like this:
<TextBlock TextAlignment="Center" FontSize="14" FontWeight="Bold" Width="10" TextWrapping="Wrap">THIS IS A TEST</TextBlock>
This is hacky, but it does work.
Just use a simple LayoutTransform..
<Label Grid.Column="0" Content="Your Text Here" HorizontalContentAlignment="Center">
<Label.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="90" />
<ScaleTransform ScaleX="-1" ScaleY="-1"/>
</TransformGroup>
</Label.LayoutTransform>
</Label>
It's doable:
Your TextBlock's TextAlignment property should be set to Center:
<TextBlock Name="textBlock1" TextAlignment="Center" Text="Stacked!" />
Then add NewLines between every character:
textBlock1.Text =
String.Join(
Environment.NewLine,
textBlock1.Text.Select(c => new String(c, 1)).ToArray());
(Uses System.Linq to create an array of strings from the individual characters in the original string. I'm sure there are other ways of doing that...)
Below XAML code changes the angle of text displayed in a textblock.
<TextBlock Height="14"
x:Name="TextBlock1"
Text="Vertical Bottom to Up" Margin="73,0,115,0" RenderTransformOrigin="0.5,0.5" >
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-90"/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
the accepted answer suggested by Ray Burns does not work for me on .net 4.0. Here is how I did it:
pull in the mscorlib
xmlns:s="clr-namespace:System;assembly=mscorlib"
put in your usercontrol/window/page resources
<s:String x:Key="SortString">Sort</s:String>
and use it like this
<ItemsControl ItemsSource="{Binding Source={StaticResource SortString}}" Margin="5,-1,0,0" />
hope it helps!
create a stackpanel with a bunch ot textblocks that take one char
make the text container's max width to allow for one char only and wrap the text:
<TextBlock TextWrapping="Wrap" MaxWidth="8" TextAlignment="Center" Text="stack" />
Make an image and fill the block with the image, use photoshop or something designed to manipulate text instead of fiddling in code ?
This code allows to have vertical text stacking and horizontal centered letters.
<ItemsControl Grid.Row="1"
Grid.Column="0"
ItemsSource="YOUR TEXT HERE"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"
HorizontalAlignment="Center"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here's a way to insert a '\n' after every character in the text of the TextBlock, that way making it display vertically:
<TextBlock x:Name="VertTextBlock" Text="Vertical Text" Loaded="VertTextBlock_Loaded"></TextBlock>
Then, in the Loaded event handler, you say:
TextBlock tb = sender as TextBlock;
StringBuilder sb = new StringBuilder(tb.Text);
int len = tb.Text.Length * 2;
for (int i = 1; i < len; i += 2)
{
sb.Insert(i, '\n');
}
tb.Text = sb.ToString();
That solution was proposed by Lette, but I believe my implementation incurs less overhead.
<linebreak/> can be used to show data in two lines
You could also use the "RUN" binding
In the App.xaml file use something like this:
<Application x:Class="Some.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:commands="clr-namespace:Deridiam.Helper.Commands"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
ShutdownMode="OnMainWindowClose"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<commands:HorizontalToVertical x:Key="HorizontalToVertical_Command"></commands:HorizontalToVertical>
<ControlTemplate x:Key="VerticalCell" TargetType="ContentControl">
<TextBlock Text="{TemplateBinding Content}" Foreground="Black"
TextAlignment="Center" FontWeight="Bold" VerticalAlignment="Center"
TextWrapping="Wrap" Margin="0" FontSize="10">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding ConvertToVerticalCmd, Source={StaticResource HorizontalToVertical_Command}}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBlock}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</ControlTemplate>
</Application.Resources>
Create the command class binded to the textblock using i:Interaction.Triggers on the Loaded event in the app.xaml example
namespace Deridiam.Helper.Commands
{
public class HorizontalToVertical
{
private ICommand _convertToVerticalCommand;
public ICommand ConvertToVerticalCmd =>
_convertToVerticalCommand ?? (_convertToVerticalCommand = new RelayCommand(
x =>
{
var tBlock = x as TextBlock;
var horizontalText = tBlock.Text;
tBlock.Text = "";
horizontalText.Select(c => c).ToList().ForEach(c =>
{
if (c.ToString() == " ")
{
tBlock.Inlines.Add("\n");
//tBlock.Inlines.Add("\n");
}
else
{
tBlock.Inlines.Add((new Run(c.ToString())));
tBlock.Inlines.Add(new LineBreak());
}
});
}));
}
}
Finally in the .xaml file where you want the vertical text to be shown
<ContentControl Width="15" Content="Vertical Text" Template="{StaticResource VerticalCell}">
</ContentControl>
Will result in:
Vertical Text
none of the above solutions solved my problem (some come close), so I'm here to post my solution and maybe help someone.
The accepted solution helped me, but the text is not aligned to the center.
<ItemsControl ItemsSource="{Binding SomeStringProperty, FallbackValue=Group 1}" Margin="5"
TextElement.FontSize="16"
TextElement.FontWeight="Bold"
TextBlock.TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding }" HorizontalAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
I will offer a solution based on the converter:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace Converters
{
[ValueConversion(typeof(object), typeof(string))]
public class InsertLineBreakConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null)
value = parameter;
if (value == null)
return null;
if (!(value is string str))
str = value.ToString();
return string.Join(Environment.NewLine, (IEnumerable<char>) str);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static InsertLineBreakConverter Instance { get; } = new InsertLineBreakConverter();
}
public class InsertLineBreakConverterExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
=> InsertLineBreakConverter.Instance;
}
}
Usage examples:
<TextBlock Text="{Binding Property, Converter={cnvs:InsertLineBreakConverter}}"/>
<TextBlock Text="{Binding Converter={cnvs:InsertLineBreakConverter}, ConverterParameter='Some Text'}"/>

Categories

Resources