Vertical alignment of WPF Checkbox content with respect to checkbox - wpf

I have a checkbox whose XAML markup is as follows:
<CheckBox HorizontalContentAlignment="Stretch">
<StackPanel Orientation="Vertical">
<TextBox x:Name="editTextBox"
Text="{Binding Path=Caption, Mode=TwoWay}"
TextWrapping="Wrap"
Visibility="{Binding Path=IsBeingEdited, Converter={StaticResource booleanToVisibilityConverter}}" />
<TextBlock x:Name="itemText"
TextWrapping="Wrap"
Text="{Binding Path=Caption}"
Visibility="{Binding Path=IsBeingEdited, Converter={StaticResource reverseBooleanToVisibilityConverter}}">
</TextBlock>
</StackPanel>
</CheckBox>
The idea is that I can switch between the TextBlock (display) and TextBox (edit). However, when running the application, the CheckBox visual (the checkable square) is vertically centered. I would like it to be aligned with the top of the TextBlock/TextBox instead.
I've noticed that when I only include a TextBlock (so no StackPanel, no TextBox), the checkbox is in fact aligned with the top of the TextBlock, so I'm assuming I'm missing some setting on the StackPanel?

First of all don't waste your time with VerticalAlignment or VerticalContentAlignment (or even ControlTemplate). They're not going to do what you want or might expect.
As described on MSDN a BulletDecorator (which is the control that CheckBox and RadioButton uses to render a radio/check button) will set the position of the icon automatically. You have no additional control over this:
A Bullet always aligns with the first line of text when the Child
object is a text object. If the Child object is not a text object, the
Bullet aligns to the center of the Child object.
Unless you change the control template (unnecessary) you'll only be able to position the radio/check icon at the top if the content is text.
So if you do something like this it won't look good because you won't be able to move the icon no matter how many VerticalAlignment properties you try to set.
<RadioButton>
<StackPanel>
<TextBlock Text="First line"/>
<TextBlock Text="Something else"/>
</StackPanel>
</RadioButton>
BUT fortunately you can put pretty much anything you want in a TextBlock using InlineUIContainer. The text (or content) in the first line will dictate the position of the icon automatically. If you want something underneath the first line that isn't text, just use <Linebreak/> and then <InlineUIContainer/>
Here's an example that has an oversized TextBox to show more clearly what's happening.
<RadioButton>
<TextBlock VerticalAlignment="Top" TextWrapping="Wrap">
<TextBlock Text="Products with <" VerticalAlignment="Center" Margin="0,0,5,0"/>
<InlineUIContainer BaselineAlignment="Center">
<TextBox FontSize="30" Width="25" Text="10" Margin="0,0,5,0"/>
</InlineUIContainer>
<TextBlock VerticalAlignment="Center" Margin="0,0,5,0">
<Run Text="days" FontWeight="Bold"/>
<Run Text="inventory" />
</TextBlock>
<LineBreak/>
<InlineUIContainer>
<StackPanel>
<CheckBox Content="Include unsold products" />
<CheckBox Content="Include something else" />
</StackPanel>
</InlineUIContainer>
</TextBlock>
</RadioButton>

CheckBox.Content doesn't give you very much control over how things are displayed. Try this instead:
<DockPanel VerticalAlignment="Top"> <!-- can also be center or bottom -->
<CheckBox/>
<Grid>
<TextBox x:Name="editTextBox"
Text="{Binding Path=Caption, Mode=TwoWay}"
TextWrapping="Wrap"
Visibility="{Binding Path=IsBeingEdited, Converter={StaticResource booleanToVisibilityConverter}}" />
<TextBlock x:Name="itemText"
TextWrapping="Wrap"
Text="{Binding Path=Caption}"
Visibility="{Binding Path=IsBeingEdited, Converter={StaticResource reverseBooleanToVisibilityConverter}}">
</Grid>
</DockPanel>

Related

WPF Mouse Binding on Listbox Item Template Inconsistent

I have a listbox which binds to an observable collection of a custom type which displays each item through my data template:
<ListBox x:Name="ListBox" Style="{StaticResource CustomListBox}" ItemsSource="{Binding HandStats}" Height="410" Width="150" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding HoleCards[0].CardParts.Value}" Margin="2"/>
<Image Source="{Binding HoleCards[0].SuitImagePath}" Width="10" Height="10" Margin="2"/>
<TextBlock Text="{Binding HoleCards[1].CardParts.Value}" Margin="2"/>
<Image Source="{Binding HoleCards[1].SuitImagePath}" Width="10" Height="10" Margin="2"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Runs:" Margin="2"/>
<TextBlock Text="{Binding NumberOfRuns}" Margin="2"/>
<TextBlock Text="Players:" Margin="2"/>
<TextBlock Text="{Binding NumberOfPlayers}" Margin="2"/>
</StackPanel>
<StackPanel.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding Path=DataContext.PopulateReport, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
CommandParameter="{Binding ElementName=ListBox, Path=SelectedItem}"/>
</StackPanel.InputBindings>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Image of my listbox:
http://imgur.com/a/QGz8z
Now ideally when I click anywhere in the stack panel for each item, the item will be selected and the command will be fired. But my problem is that the item selection and the command firing is not working as it should.
The item will only become selected if I click in between the text blocks or in the empty space to the right of the text blocks, but the command will not be fired. The command will only fire once I have firstly selected the item, and then click again onto one of the text blocks or one of the images.
I'm still quite new to WPF so if I'm not making much sense please let me know, thanks in advance :)
So instead of using input bindings I decided to use a different method. I created a property in my vm and bound this to the selected item of my list. So now every time I select a new item (which works perfectly now) the property is updated in my vm. Simple!
Try to set the Background property of the StackPanel to Transparent:
<StackPanel Orientation="Vertical" Background="Transparent">
...
If it doesn't have a Background the click events won't be raised as expected.

Fill visible border in StackPanel

I put 2 borders inside stackpanel and it should be one border is visible at a time .
I like the visible border to fill stackpanel
<StackPanel>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Title_RoleVisibilty,
Converter={StaticResource WriteRoleVisibilityToVisibilityConverter}}">
<TextBox Text="{Binding Title}" MaxLength="50" />
</Border>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Title_RoleVisibilty ,
Converter={StaticResource ReadRoleVisibilityToVisibilityConverter}}">
<TextBlock Text="{Binding Title }" />
</Border>
</StackPanel>
I used stackpanel /Dockpanel and both not filled the desired border filled
Please advice
The duplication in the borders is adding unnecessary problems. Limit the situation to only one border. Hence you don't have to focus on the border visibility, with only one border and you can the put in styles(?) maybe to focus on the difference needed for the target parameters instead.
For example to solve the problem I have taken your example and added a new binding on MaxLength size which will adjust as needed; for that appears to be the only change required.
<StackPanel>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center" >
<TextBox Text="{Binding Title}" MaxLength="{Binding MaxSize, Converter=???" />
</Border>
</StackPanel>

WPF MVVM customizing ListView cell to insert hyperlink and change text color

I have a GridView cell in a ListView that is defined as a TextBlock and bound to a string on my ViewModel. I want to be able to change parts of the text into hyperlinks and part into different colors programatically.
Here is the XAML for the GridView cell:
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="#dfdfdf" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Data}" Margin="3"/>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
And here's what it looks like at the moment:
An example of the text that is bound would be:
<color:#ff0000>Test item</color>
Test item 2
<link:http://www.google.com>Test hyperlink</link>
I have no problem with the regex to parse the bound text and pull out the required information but how would I go about changing the TextBlock into different colors and add a hyperlink?
Thanks in advance
You can put multiple Run elements inside a TextBlock and style then however you like.
Here is an example with a working hyperlink which even supports MVVM :)
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="#dfdfdf" HorizontalAlignment="Stretch">
<TextBlock Margin="3">
<Run Text="{Binding Data}" />
<Run Text="Some more data" Background="Red" />
<Run Text="Click Me" Foreground="Blue" TextDecorations="Underline" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<local:EventToCommand Command="{Binding LinkClickCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Run>
</TextBlock>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
Note:
The Interaction.Triggers are from System.Windows.Interactivity and the EventToCommand from MVVMLight.
Similar to Blachshma's answer, but using a hyperlink right in there with the Run objects:
<TextBlock>
<Run Text="{Binding Data}" />
<Run Text="Some more data" Background="Red" />
<Hyperlink Command="{Binding Path=Command}">
<TextBlock Text="{Binding Path=Text}"/>
</Hyperlink>
</TextBlock>
Clearly I have a Command and Text properties to bind to for the hyperlink. Will look exactly the same, but will also respond to the command's CanExecute predicate (hyperlinks go grey).

Silverlight textblock in a listbox not wrapping

I have a data bound Listbox as shown below. I want the textblock that holds the data to wrap. And I have not been able to.
What is the problem here?
Here is my code:
<DataTemplate x:Key="policyLbTemplate">
<StackPanel>
<TextBlock Text="{Binding name}" FontWeight="Bold"/>
<TextBlock Text="{Binding description}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
<ListBox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="{Binding Policies}"
ItemTemplate="{StaticResource policyLbTemplate}"
HorizontalContentAlignment="Stretch" />
You need to add one property to the list box: ScrollViewer.HorizontalScrollBarVisibility="Disabled", then the text will wrap (otherwise it grows offscreen). I have done it in the following code and it works fine for me.
<ListBox Name="lstbIcons" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding UserActionName}" FontWeight="Bold"/>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is most likely because there is nothing restricting the width of the TextBlock so that it is growing offscreen. Do Horizontal scrollbars appear?
See the following related questions and try the solutions described:
WP7 TextBlock inside a ListBox not wrapping text
Force TextBlock to wrap in WPF ListBox
windows phone 7 TextBlock TextWrapping not honored in listbox
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/37236ac6-05c3-4acc-baca-abc871ba64e0

Binding in Label.ContentTemplate

In the Xaml below, the first control (the TextBlock by itself) has no problem binding and rendering the value of RecordCount. But in the second control (the Label with the ContentTemplate), the value of RecordCount is not rendered. However, the literal "Cars" is rendered fine. So I know the ContentTemplate is working, but the binding to RecordCount from within the ContentTemplate is not. What am I doing wrong?
<TextBlock Text="{Binding RecordCount}"/>
<Label HorizontalAlignment="Center" >
<Label.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="100">
<TextBlock Text="{Binding RecordCount}"/>
<TextBlock Text=" Cars"/>
</StackPanel>
</DataTemplate>
</Label.ContentTemplate>
</Label>
Set the Content property on the Label to the current DataContext:
<Label HorizontalAlignment="Center" Content="{Binding}">
or, set the StackPanel as the Content and don't use a template at all:
<Label HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" Width="100">
<TextBlock Text="{Binding RecordCount}"/>
<TextBlock Text=" Cars"/>
</StackPanel>
</Label>
The ContentTemplate is used to present the Content. Since it is null, the DataContext is null when your template is instantiated. The TextBlocks are still created, so Cars is rendered, but null doesn't have a RecordCount property so the first text block is rendered with no text.
Also, if you are only using two TextBlocks to concatenate text, you can use the StringFormat property in .NET 3.5 SP1 or later:
<Label Content="{Binding RecordCount}" ContentStringFormat="{}{0} Cars"/>
Just an alternative, you can bind the RecordCount to Label's Content and have DataTemplate takes care on how you are going to show it.
<Label HorizontalAlignment="Center" Content="{Binding RecordCount}" >
<Label.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="100">
<TextBlock Text="{Binding}"/>
<TextBlock Text=" Cars"/>
</StackPanel>
</DataTemplate>
</Label.ContentTemplate>
</Label>

Resources