Label.TextAlign is of type ContentAlignment. It allows developer to choose any combination of vertical and horizontal alignments.
TextBox.TextAlign is of type HorizontalAlignment. It only allows Left, Center and Right.
I would like to imitate behavior of ContentAlignment = MiddleLeft for a TextBox.
Basically, I am trying to create a custom MsgBox dialog (MessageBox.Show for non-VB developers). Microsoft's MsgBox seems to have its Label.TextAlign = MiddleLeft automatically set through windows API. I need it to be a TextBox (not a Label), because users should be able to select text and copy to clipboard, partially or in full.
So far I came up with this solution:
Have a TableLayoutPanel, one of its cells will contain the above TextBox.
Set Anchor = Left,Right. This will keep it stretched horizontally.
MeasureText just before showing (example: Form_Load), and adjust TextBox.Height.
Dim size As SizeF = TextBox1.CreateGraphics.MeasureString(
TextBox1.Text, TextBox1.Font, TextBox1.Width)
TextBox1.Height = size.Height
Here is a picture of how it works in action (demo project, not yet a custom MsgBox):
It seems like a rather dirty approach, not resilient to resizing and text changes. These events can be handled accordingly, of course, but it adds to the overall clutter.
Question: Is there a cleaner approach? I am looking for anything that may help implement the above behavior - it does not necessarily have to a be a TextBox.
If you add a WPF ElementHost to your form. Then create a WPF UserControl with a TextBox in it like so:
<UserControl x:Class="UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="113" d:DesignWidth="234" BorderThickness="2" BorderBrush="Black">
<TextBox x:Name="TextBox1" BorderThickness="0" IsReadOnly="True" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">Hello World</TextBox>
</UserControl>
Then in your code you can set the value like this:
Me.UserControl11.TextBox1.Text = "Some Text Value Here"
Naturally, this assumes that you can use WPF, but on the plus side, you have all the Xaml styling capabilities at your disposal.
Related
does anyone know how to set text of textbox in vertical center of the box? I'm trying to make my universal app responsive, and textbox size adapts as it should, but I would need text in to be always in vertical center.
Thanks for all your time and help in advance!
My code:
<TextBox
x:Name="textBox"
Margin="10"
TextWrapping="Wrap"
Text=""
Grid.Column="1"
PlaceholderText="Website"
TextAlignment="DetectFromContent"
FontSize="20"
FontFamily="Segoe UI Light"
VerticalContentAlignment="Center"
d:LayoutOverrides="TopPosition, BottomPosition" />
There's a little more to it than that. Inside the template for TextBox are several elements. Including presenters for the placeholder text and a delete button etc.
You could add an attached property to target the embedded ScrollViewer and achieve most of what you want like this;
<TextBox ScrollViewer.VerticalContentAlignment="Center" ..../>
Except if you're using placeholder "watermark" text and stuff, you may have to make a copy of the template and vertical position everything in there.
Hope this helps, cheers.
For example we have a Border. What the difference beetween these XAMLs?
1) Background="Transparent"
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Border
BorderBrush="White"
BorderThickness="2"
Width="400"
Height="400"
Background="Transparent"
PointerPressed="Border_PointerPressed"
PointerReleased="Border_PointerReleased" />
</Grid>
2) Background="{x:Null}"
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Border
BorderBrush="White"
BorderThickness="2"
Width="400"
Height="400"
Background="{x:Null}"
PointerPressed="Border_PointerPressed"
PointerReleased="Border_PointerReleased" />
</Grid>
Both of these borders looks identical. But what the difference?
The difference is if we set null background the Border will not support hit-testing, that's why routed events like PonterPressed will not be raised.
Conversely though, if we set Transparent background events will be raised.
To illustrate this let's write code-behind.
using Windows.UI.Xaml.Media;
namespace App1 {
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
}
void Border_PointerPressed(object sender, PointerRoutedEventArgs e) {
Border border = sender as Border;
if (border != null)
border.Background = new SolidColorBrush(Colors.Red);
}
void Border_PointerReleased(object sender, PointerRoutedEventArgs e) {
Border border = sender as Border;
if (border != null)
border.Background = new SolidColorBrush(Colors.Transparent);
}
}
}
1) Let's use the first XAML, compile our app and run it. Try to tap inside the square. The square becomes red because the events are rised and the handlers calls.
2) Now let's use the second XAML, compile the app, run it, tap inside the square. Nothing happens because the events are not rised. The handlers are not calls.
For completeness, I found this link http://msdn.microsoft.com/en-us/library/hh758286.aspx#hit_testing explaining this rather well - see especially the second bullet point:
Hit testing and input events
Determining whether and where in UI an element is visible to mouse,
touch, and stylus input is called hit testing. For touch actions and
also for interaction-specific or manipulation events that are
consequences of a touch action, an element must be hit-test visible in
order to be the event source and fire the event that is associated
with the action. Otherwise, the action passes through the element to
any underlying elements or parent elements in the visual tree that
could interact with that input. There are several factors that affect
hit testing, but you can determine whether a given element can fire
input events by checking its IsHitTestVisible property. This property
returns true only if the element meets these criteria:
The element's Visibility property value is Visible.
The element's Background or Fill property value is not null. A null Brush value results in transparency and hit test invisibility. (To
make an element transparent but also hit testable, use a Transparent
brush instead of null.) Note Background and Fill aren't defined by
UIElement, and are instead defined by different derived classes such
as Control and Shape. But the implications of brushes you use for
foreground and background properties are the same for hit testing and
input events, no matter which subclass implements the properties.
If the element is a control, its IsEnabled property value must be true.
The element must have actual dimensions in layout. An element where either ActualHeight and ActualWidth are 0 won't fire input events.
I'm new to Windows Phone apps development, and I've created a scrolling menu using the following xaml code :
<ScrollViewer HorizontalAlignment="Left" Margin="18,0,0,0" Name="scrollViewer1" VerticalAlignment="Top" Width="450" HorizontalScrollBarVisibility="Auto" Grid.Row="1">
<StackPanel Height="Auto" Name="stackPanel1" Width="Auto">
<Button Height="620" FontSize="120" Name="gotoGmail" Width="Auto">Gmail</Button>
<Button Height="620" FontSize="120" Name="gotoYahoo" Width="Auto">Yahoo</Button>
</StackPanel>
</ScrollViewer>
I'd like to know whether it's possible to start an event once the user scrolls the menu from one button to another. If it is possible, i'd be grateful if you could explain how. If it's not , i'd like to hear about how could I do it using different tools rather than ScrollViewer. Thanks in advance !
There's no "Scrolled" event on the ScrollViewer, but what you can do is two-way bind a property to VerticalOffset. That lets you trigger an event/command from your view/viewmodel when the scroll changes.
Something like this:
<ScrollViewer VerticalOffset="{Binding VerticalOffset,Mode=TwoWay}" ...
And then in the data context:
public double VerticalOffset
{
get { return _verticalOffset; }
set
{
_verticalOffset = value;
// call "on scroll changed" actions here
}
}
private double _verticalOffset = 0;
how could I do it using different tools rather than ScrollViewer
You can of course make a scrolling menu using other approaches. I'll bet there is some nifty approach you could figure, using the WinRT transitions/animations stuff, but I'm not familiar enough with those to say. Here are some others (not sure which would be best/easiest for your scenario):
Probably using Canvas would be a quick-and-dirty way to do it (just set up buttons that set off Canvas.Left and Canvas.Top animations).
Extending ItemsControl along with a custom ControlTemplate would be a good approach if you want to create a re-usable component.
I like extending Panel, but you have to do the animations manually using a DispatcherTimer, and you have to lay out the buttons yourself using Measure and Arrange.
Why does this code produce the error in a Windows 8 XAML application?
Value does not fall within the expected range.
The XAML:
<SemanticZoom>
<SemanticZoom.ZoomedInView>
<ListView
Style="{StaticResource HorizontalListViewStyle}"
SelectionMode="None"
ScrollViewer.IsHorizontalScrollChainingEnabled="False"
ItemsSource="{Binding BoardItems}"
ItemContainerStyle="{StaticResource ZoomedOutListViewItemContainerStyle}"
...
The MVVM code:
ObservableCollection<WritingBoardModel> boards = new ObservableCollection<WritingBoardModel>();
... // Add item models to boards.
CollectionViewSource v = new CollectionViewSource()
{
Source = boards,
};
this.ViewModel.Add(BoardItemsViewModelKey, v);
If I skip the CollectionViewSource and directly add the boards instance to my view model, then it all works.
I think I need to use a CollectionViewSource in order to get some semantic zoom selection behaviour to work.
So, CollectionViewSources are weird and the way you have to bind to them is weird as well. To give you an example, in order to do it 'by the book' (the way the sample projects do), I've found it practically has to be a StaticResource as such:
<Page.Resource>
<CollectionViewSource Source="{Binding Whatev}"
x:Key="WhatevSource"/>
</Page.Resource>
<GridView ItemsSource="{Binding Source={StaticResource WhatevSource}}"/>
Notice that we're not setting the source directly to the CollectionViewSource, but we're setting a 'pathless' Binding, basically using the CollectionViewSource as a DataContext (just one way to think of it, not actually technically correct).
This is the only way I've been able to get it to work, though I believe you can technically in the codebehind set the ItemsSource directly to the View of the CollectionViewSource or something similar.
In your Listview add "StaticResource" and "Source"
<ListView ItemsSource="{Binding Source={StaticResource WhatevSource}}"/>
I needed to bind to the View property of the CollectionViewSource like this:
CollectionViewSource v = new CollectionViewSource()
{
IsSourceGrouped = false,
Source = boards,
};
this.ViewModel.Add(BoardItemsViewModelKey, v.View);
Mind you, this doesn't help with my two ListViews and keeping them in selection synch in a SemanticZoom.
How would I set the number of characters a user is allowed to input in a TextBlock in xaml?
Would I do it on the Model or create some sort of custom attribute to handle it?
TextBlock doesn't have a MaxLength, neither does Label. TextBox does. Users cannot input into a TextBlock unless you have modified it.
Is it really a TextBlock you want to limit or did you mean a TextBox? If it is a TextBox you can simply use the MaxLength property.
<TextBox Name="textBox1" MaxLength="5" />
If it really is a TextBlock you are using and somehow allowing a user to input data into it, then switch to use a TextBox. If it is the TextBlock style you are after, you can style the TextBox to look like a TextBlock.
Without creating a custom control, you have a few options.
You could try to size the TextBlock to fit your expected text exactly, but that gets ugly fast trying to account for varying input or different font sizes.
Instead, you can verify the character length of the string to be assigned to the TextBlock.Text property and limit it if necessary.
string s = "new text";
if (s.Length > maxLen)
textBlock1.Text = s.Substring(0, maxLen);
else
textBlock1.Text = s;
Another option is to use the TextWrapping and TextTrimming properties. The following attributes could be added to your TextBlock xaml to add line wrapping and "..." to denote that text exists beyond the size of the TextBlock.
<TextBlock ... TextWrapping="Wrap" TextTrimming="CharacterEllipsis" />
You can use 'TextTrimming' Property of a Textblock. Set TextTrimming = "CharacterEllipsis". You might need to play with Width to manage how many characters you really want to display.
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding Subject}"/>
Either Set MaxHeight = "SomeHeight" and trim the overflow with
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding LongText}"
Or Use TextBox like Textblock by setting
<TextBox IsReadOnly="True" Background="Transparent" BorderThickness="0"
MaxLength="100"