WPF Trigger on TextBlock Inlines - c#

I have a TextBlock that I want to display a user name, and email like this:
Firstname Lastname (Email)
However, I don't want to put the (Email) part in if the user doesn't have an email on file. I would also like to italicize the email. Normally, I would use a TextBlock and add Runs in for the various parts of the text, but I can't find a way to dynamically change a TextBlock's inlines from XAML.
I've tried this:
<TextBlock.Triggers>
<DataTrigger Binding="{Binding Path=HasEmail}" Value="True">
<Setter Property="Inlines" TargetName="contactTagNameEmailTextBlock">
<Setter.Value>
<Run Text="{Binding Path=Firstname}" />
<Run Text="{Binding Path=Lastname}" />
<Run Text="(" />
<Run Text="{Binding Path=Email}" />
<Run Text=")" />
</Setter.Value>
</Setter>
</DataTrigger>
</TextBlock.Triggers>
But VS complains that the value is set more than once (due to the multiple Run's). How can I get around this? Alternatively, it would be really convenient if I could set a binding on a whole FrameworkElement. For example, if I could just put a placeholder in my Grid where I want to put a custom control I construct in code behind on this bound object, that would be the best.
Thanks.

Something like that should work :
<Window.Resources>
<BooleanToVisibility x:Key="visibilityConverter"/>
</Window.Resources>
...
<TextBlock>
<Run Text="{Binding Path=Firstname}" />
<Run Text="{Binding Path=Lastname}" />
<TextBlock Visibility="{Binding HasEmail, Converter={StaticResource visibilityConverter}}">
<Run Text="(" />
<Run Text="{Binding Path=Email}" />
<Run Text=")" />
</TextBlock>
</TextBlock>

Look into Multibinding and StringFormat
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}">
<Binding Path="LastName" />
<Binding Path="FirstName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
You should be able to hide the () if email isn't there.

The answer here that says to nest TextBlock elements will cause issues with layout. For instance, the outer TextBlock will no longer properly respect TextTrimming settings.
Here's a better approach which gives you the flexibility of runs set via a trigger* which still allow proper layout.
Note: I added the formatting properties (Foreground, Bold) to show why you would use Runs here instead of a simple multi-binding. Using Runs (or any inlines) allows you to format the text of a TextBlock, but still have it respect layout (i.e. TextTrimming works as expected, etc.)
<ContentControl x:Name="TextBlockPresenter">
<TextBlock TextTrimming="CharacterEllipsis" IsHitTestVisible="False">
<Run Text="{Binding Path=Firstname}" />
<Run Text="{Binding Path=Lastname}" FontWeight="Bold" />
<Run Text="(" Foreground="Gray" />
<Run Text="{Binding Path=Email}" Foreground="Gray" />
<Run Text=")" Foreground="Gray" />
</TextBlock>
</ContentControl>
[SomeTriggerArea]
<DataTrigger Binding="{Binding Path=HasEmail}" Value="False">
<Setter TargetName="TextBlockPresenter" Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<TextBlock TextTrimming="CharacterEllipsis" IsHitTestVisible="False">
<Run Text="{Binding Path=Firstname}" />
<Run Text="{Binding Path=Lastname}" FontWeight="Bold" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
[/SomeTriggerArea]
* Technically you aren't setting the runs via a trigger. You're setting an entirely new template which has a TextBox that has the proper runs defined.
It's also a good idea to set IsHitTestVisible to False if you're using Runs like this in a control which you may want to respond to mouse hits, then walk the visual tree (i.e. a TreeView where you listen to a right mouse-down, walk the tree to find the TreeViewItem and set IsSelected to true.) This is because the runs will respond to the mouse, but they aren't a FrameworkElement so when you call VisualTreeHelper.GetParent using e.OriginalSource, you'll get an exception. Simply disabling the TextBlock from participating in the mouse events avoids that.

Related

Conditional Context Menu Triggers

I currently have two buttons. One button is to Showappointments(), the other is ShowTask(). When either is clicked the FontWeight of that button goes to bold. Only one can be bolded at a time. I use that as the indicator to show which is being displayed.
The values are then displaye in a ListBox. I'm trying to have a condition such that when ShowTask fontweight is Bold it'll display the corresponding contextMneu for the Task, and it'll display a different set of contextmenus for Appointments.
<ListBox ItemsSource="{Binding FilteredEventsCollection}"
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AppointmentBold}" Value="Bold">
<Setter Property="ContextMenu" Value="{StaticResource Menu1}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel cal:Message.Attach="[Event MouseDoubleClick] = [Action Open()]">
<TextBlock Text="{Binding Date, StringFormat=g}" Foreground="Black" FontWeight="Bold" FontFamily="Segoe UI"/>
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Company}" Foreground="Black"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
User Control Resources
<ContextMenu x:Key="TaskMenu">
<MenuItem>Open This Task</MenuItem>
</ContextMenu>
<ContextMenu x:Key="AppointmentMenu">
<MenuItem>Open This Appointment</MenuItem>
</ContextMenu>
This piece of code crashes right away, I'm wondering if I'm approaching correct and if I can get some guidance

Windows Phone textoutlining

is it possible to outline text in windows phone 8, for example I have red text, but I want the outline to be black?
Should I do this in xaml of C#, and also if possible how? any examples will be much appreciated
thanx
Here you can see how it WAS DONE: http://blog.mrlacey.co.uk/2010/06/silverlight-effects-and-windows-phone-7.html
It's not working anymore. Microsoft removed it, due to performance issues.
The performance hit that applications took from using these effects put too much of a strain on the system and it was decided that if we couldn’t deliver a perfomant feature we would disable until such a time as we could.
The only possibility would be to create 2 TextBlocks and change the FontSize, RenderTransfor, FontWeight,...
<TextBlock Text="{Binding ElementName=BackgroundText,Path=Text}" FontSize="25" Foreground="Red" FontWeight="ExtraBold">
</TextBlock>
<TextBlock Text="Hello" Name="BackgroundText" FontSize="25" Foreground="White" FontWeight="Bold">
<TextBlock.RenderTransform>
<TranslateTransform X="0.5" Y="0" />
</TextBlock.RenderTransform>
</TextBlock>
</TextBlock>
Since two TextBlocks with different FontWieghts won't help you with large text (just longer than simple "Hello") because bolder text will be ahead of thin one, I recommend you to use 4 TextBlocks shifted by 1 upper-left, upper-right etc. and set Opacity = 0.5 to smoothen the outline.
Here an example:
<TextBlock Grid.Row="0" Text="Outlined text" Style="{StaticResource OutlineTb}">
<TextBlock.RenderTransform>
<TranslateTransform X="-1" Y="1" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock Grid.Row="0" Text="Outlined text" Style="{StaticResource OutlineTb}">
<TextBlock.RenderTransform>
<TranslateTransform X="-1" Y="-1" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock Grid.Row="0" Text="Outlined text" Style="{StaticResource OutlineTb}">
<TextBlock.RenderTransform>
<TranslateTransform X="1" Y="-1" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock Grid.Row="0" Text="Outlined text" Style="{StaticResource OutlineTb}">
<TextBlock.RenderTransform>
<TranslateTransform X="1" Y="1" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock Grid.Row="0"
Text="Outlined text"
FontSize="25"
Foreground="White"
FontWeight="Normal">
</TextBlock>
And style:
<Style TargetType="TextBlock" x:Key="OutlineTb">
<Setter Property="FontSize" Value="25" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Opacity" Value="0.5" />
</Style>
But keep in mind that it's quite "heavy" solution and still not as good as genuine outline.

How call an event when click on part of text in text block?

iHi, in my Windows Phone application in View I have:
<TextBlock x:Name="lblink" FontSize="15" Margin="30,0,24,0" Height="30" Text="*use a email#mail.com if you are not the member" TextWrapping="Wrap" HorizontalAlignment="Left" />
I need to make the functionality like this: when I click on the text: "email#mail.com" it should be called an event
How can I resolve this issue?
So, try using following code:
<StackPanel Orientation="Horizontal">
<TextBlock Text="*use a "/>
<TextBlock Text="email#mail.com" Tap="TextBlock_Tap"/>
<TextBlock Text=" if you are not the member"/>
</StackPanel>
Why not use a HyperlinkButton. This allows you to set text in the Content property, and then implement the Click event handler.
Alternatively, you could use a Template for a button control:
<phone:PhoneApplicationPage.Resources>
<ControlTemplate x:Key="MyButtonTemplate" TargetType="Button">
<TextBlock x:Name="lblink" FontSize="15" Margin="30,0,24,0" Height="30" Text="*use a email#mail.com if you are not the member" TextWrapping="Wrap" HorizontalAlignment="Left" />
</ControlTemplate>
</phone:PhoneApplicationPage.Resources>
Which is implemented as follows:
<Button x:Key="MyButton" Template="{StaticResource MyButtonTemplate}" Click="MyButton_Click" />
You can then do whatever you need to in the MyButton_Click event handler.
<TextBlock>
<Run Text="*use a " />
<Hyperlink Click="[click event]">
<Run Text="email#mail.com" />
</Hyperlink>
<Run Text=" if you are not the member" />
</TextBlock>
This provides you the clickable region I think you are looking for.

Textblock selected foreground color in datagrid WPF

I have created a datagrid in WPF...
I have defined several custom Columns..
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding HeadC}" />
<TextBlock Text="{Binding HeadCPercent}" Foreground="#FFF05D1D" />
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
The problem is that when a row is slected the seconds textblock color doesnt change and it is hardly visible...
Any solution to this problem ?
Add DataTrigger to the DataTemplate triggers collection that would change foreground based on selected state of the row. Like in the following example:
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding HeadC}" />
<TextBlock x:Name="tbPercent" Text="{Binding HeadCPercent}" Foreground="#FFF05D1D"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dg:DataGridRow}}}" Value="True">
<Setter Property="Foreground" TargetName="tbPercent" Value="Blue" />
</DataTrigger>
</DataTemlate.Triggers>
</DataTemplate>
I took this answer as a basis and adjusted it to your question. I could made a typo in the code but you should get the idea :). Hope it helps.

Styling individual cells in a listview

On the internet I found many examples of styling a complete column or complete row in a listview.
I need to be able to dynamically style individual cells in the listview. How can I access the properties of individual items in a row?
If you've got a finite number of properties in your data objects that you want to use to style your items, you can create data templates and styles, and use data triggers to switch between them. I've used something like this to alter the appearance of data objects in a list based on if they are "active/inactive" and to create a collapsed/expanded version of the object based on whether it's selected or not.
You can also use converters (built-in or custom) to get some effects easily. For example, I used a built-in boolean to visibility converter to hide/unhide the combobox/textblock in my TaskSelectedTemplate based on if the object's IsActive member.
<DataTemplate x:Key="TaskSelectedTemplate">
<Grid Margin="4">
...
<Border Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 4 0"
BorderThickness="0"
CornerRadius="2">
<Border.Background>
<MultiBinding Converter="{StaticResource ActiveToColor}">
<Binding Path="."/>
<Binding Path="IsActive"/>
<Binding Path="IsPaused"/>
</MultiBinding>
</Border.Background>
</Border>
<StackPanel Grid.Row="0" Grid.Column="1"
Orientation="Horizontal"
Margin="0 2">
<ComboBox ItemsSource="{Binding Source={StaticResource TaskTypes}}"
SelectedItem="{Binding Type}"
Text="{Binding Type}"
Visibility="{Binding IsActive, Converter={StaticResource BoolToVis}}"/>
<TextBlock Text="{Binding Type}"
FontWeight="Bold"
Visibility="{Binding IsActive, Converter={StaticResource InvBoolToVis}}"/>
<TextBlock Text=" task"/>
</StackPanel>
...
</Grid>
</DataTemplate>
<DataTemplate x:Key="TaskNotSelectedTemplate">
<Grid Margin="4">
...
<Border Grid.Row="0" Grid.Column="0" Grid.RowSpan="4" Margin="0 0 4 0"
BorderThickness="0"
CornerRadius="2">
<Border.Background>
<MultiBinding Converter="{StaticResource ActiveToColor}">
<Binding Path="."/>
<Binding Path="IsActive"/>
<Binding Path="IsPaused"/>
</MultiBinding>
</Border.Background>
</Border>
<TextBlock Grid.Row="0" Grid.Column="1"
Text="{Binding Type}"/>
<TextBlock Grid.Row="0" Grid.Column="2"
TextAlignment="Right">
<Run Text="{Binding Length.TotalMinutes, StringFormat='0', Mode=OneWay}"/>
<Run Text=" min"/>
</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="3"
TextAlignment="Right">
<Run Text="{Binding TimesPerformed, Mode=OneWay}"/>
<Run Text=" tasks"/>
</TextBlock>
</Grid>
</DataTemplate>
<Style x:Key="ContainerStyle" TargetType="{x:Type ListBoxItem}">
<!--this part changes the selected item highlight color-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="Border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border"
Property="Background" Value="#2000BFFF">
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--this part causes selected task to expand-->
<Setter Property="ContentTemplate" Value="{StaticResource TaskNotSelectedTemplate}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource TaskSelectedTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
For more complex scenarios, you might want to look at DataTemplateSelector. I've never used it, but it seems like it might be ideal if you've got a lot of data templates to juggle.
Generally speaking, you shouldn't need this. Assuming you are using GridView, you should be able to use CellTemplate or CellTemplateSelector of your GridViewColumns.
If you really want to access specific cells, I think there is no clean way, you'd be better using DataGrid (from .Net 4 or WPF toolkit for .Net 3.5). With that, you can do something like this:
((TextBlock)datagrid.Columns[1].GetCellContent(m_specificItem)).Background = Brushes.Red

Categories

Resources