WPF create button with custom content template - c#

I have application in WPF where I need to create a number of buttons with the same content layout. It is currently defined in the Window as:
<Button Grid.Row="0" Grid.Column="0" Margin="4" >
<Button.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.85*" />
<RowDefinition Height="0.25*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" TextAlignment="Center" Text="Primary Text that can wrap" TextWrapping="Wrap" FontSize="14.667" />
<TextBlock Grid.Row="1" TextAlignment="Left" Text="smaller text" FontSize="10.667" />
</Grid>
</Button.Content>
</Button>
What I would ideally like to do is change that to:
<controls:MultiTextButton Grid.Row="0" Grid.Column="0" PrimaryText="Primary Text that can wrap" SecondaryText="smaller text" />
Rightly or wrongly I've created the following class:
public class MultiTextButton : Button
{
public static readonly DependencyProperty PrimaryTextProperty = DependencyProperty.Register("PrimaryText", typeof(String), typeof(MultiTextButton));
public static readonly DependencyProperty SecondaryTextProperty = DependencyProperty.Register("SecondaryText", typeof(String), typeof(MultiTextButton));
static MultiTextButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiTextButton), new FrameworkPropertyMetadata(typeof(MultiTextButton)));
}
public string PrimaryText
{
get { return (string)GetValue(PrimaryTextProperty); }
set { SetValue(PrimaryTextProperty, value); }
}
public string SecondaryText
{
get { return (string)GetValue(SecondaryTextProperty); }
set { SetValue(SecondaryTextProperty, value); }
}
}
I'm now unsure of how to set the 'template' to display the content in the format as the original code in the Window. I've tried:
<ControlTemplate x:Key="MultiTextButtonTemplate" TargetType="{x:Type controls:MultiTextButton}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.85*" />
<RowDefinition Height="0.25*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" TextAlignment="Center" Text="{Binding PrimaryText}" TextWrapping="Wrap" FontSize="14.667" />
<TextBlock Grid.Row="1" TextAlignment="Left" Text="{Binding SecondaryText}" FontSize="10.667" />
</Grid>
</ControlTemplate>
but in Blend and Visual Studio the button is not rendered.

You're after TemplateBinding:
<TextBlock Grid.Row="0" TextAlignment="Center" Text="{TemplateBinding PrimaryText}" TextWrapping="Wrap" FontSize="14.667" />
<TextBlock Grid.Row="1" TextAlignment="Left" Text="{TemplateBinding SecondaryText}" FontSize="10.667" />
This binding is for use specifically in control templates -- it refers to a dependency property in the control. (Note that a regular binding, by contrast, refers to a property in the current DataContext.)
Edit
To make it look like a button, copy the default control template for Button and replace its ContentPresenter with something like below:
<ContentControl Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"
ContentTemplate="{TemplateBinding ContentTemplate}">
<ContentControl.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.85*" />
<RowDefinition Height="0.25*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" TextAlignment="Center" Text="{Binding PrimaryText}" TextWrapping="Wrap" FontSize="14.667" />
<TextBlock Grid.Row="1" TextAlignment="Left" Text="{Binding SecondaryText}" FontSize="10.667" />
</Grid>
</ContentControl.Content>
</ContentControl>

Related

WPF TextBox not trimming in DataTemplate

I have an odd problem with TextBox with TextTrimming set to CharacterElipsis used in a DataTemplate in WPF application. At the start of application everything works fine. But when I am resizing the window - reducing the width, the trimming is not working.
In an example below:
<Grid>
<DockPanel>
<DockPanel.Resources>
<DataTemplate x:Key="lowerLevel" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="34*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="14*" />
</Grid.ColumnDefinitions>
<TextBlock Text="textboxvalue1" Grid.Column="0" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue2" Grid.Column="1" FontWeight="Bold" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue3" Grid.Column="2" FontWeight="Bold" VerticalAlignment="Center" Margin="0,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<CheckBox IsChecked="True" Content="ApprovedText" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" Margin="0,10,15,10" />
</Grid>
</DataTemplate>
</DockPanel.Resources>
<ListView x:Name="listViewControl" ItemTemplate="{StaticResource lowerLevel}" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
</DockPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="34*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="26*" />
<ColumnDefinition Width="14*" />
</Grid.ColumnDefinitions>
<TextBlock Text="textboxvalue1" Grid.Column="0" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue2" Grid.Column="1" FontWeight="Bold" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Text="textboxvalue3" Grid.Column="2" FontWeight="Bold" VerticalAlignment="Center" Margin="0,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<CheckBox IsChecked="True" Content="ApprovedText" FontWeight="Bold" Grid.Column="3" VerticalAlignment="Center" Margin="0,10,15,10" />
</Grid>
</Grid>
I am having two identical Grids, but first one is placed in a DataTemplate and the second is just a separate control. TextBoxes in bottom grid are trimming correctly, when resizing window, however the TextBoxes from DataTemplate do not fit the width of parent columns while window resizing.
The code behind is:
public partial class MainWindow : Window
{
private ListCollectionView comparedFamiliesView;
public ListCollectionView ComparedFamiliesView
{
get
{
if (comparedFamiliesView == null)
{
comparedFamiliesView = new ListCollectionView(new List<Object>() { new Object(), new Object(), new Object() });
}
return comparedFamiliesView;
}
}
public MainWindow()
{
InitializeComponent();
listViewControl.ItemsSource = ComparedFamiliesView;
}
}
It basically adds three objects to have something to view on ListView.
I was trying different combinations of VerticalAlignment, VerticalContentAlignment - didn't work.
What I have tried was to place each TextBox in separate Grid in order to bind its Width to TextBox Width or MaxWidth, like:
<Grid Grid.Column="0" x:Name="grid1">
<TextBlock Text="textboxvalue1" FontWeight="Bold" VerticalAlignment="Center" Margin="15,10,0,10" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" MaxWidth="{Binding ActualWidth, ElementName=grid1}" />
</Grid>
Didn't work either.
How can I force TextBoxes in DataTemplate to behave the same way as those in separate Grid?
Or what am I doing wrong with TextTrimming when using in DataTemplate.
Thank you for your help!!!
Regards,
Ariel
Try to set the ScrollViewer.HorizontalScrollBarVisibility attached property of the ListView to Disabled:
<ListView x:Name="listViewControl" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ...

Getting selected item in ListView without selecting an Item on UI

I'm working on a WPF application where I've made a ListView on UI which is two-way binding enabled. This WPF application is being developed for a windows 10 based smartphone. So whenever a user taps an item in the list whose data source is data-binded to back data collection, I've to do some operation for that item in code behind.
Now the problem is, I always receive a null object from the below function whenever the user taps on the item.
CartItem selectedItem = (CartItem)lv_CartItems.SelectedItem;
I only get a filled item object when the user actually selects an item by clicking on ListViewItem rather than tapping on it.
I want to get the selected item when the user taps on it. Is there any workaround available in WPF this problem? I've stuck here
My ListViewItem template looks like this.
<ListView Name="lv_CartItems" Loaded="lv_CartItems_Loaded"
HorizontalAlignment="Center" ScrollViewer.CanContentScroll="False"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Width="250" Height="230" SelectionMode="Single"
>
<ListView.ItemTemplate>
<DataTemplate>
<Viewbox>
<Grid Width="230" Height="110" >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width=".1*" />
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1"
Grid.Row="0" Grid.Column="0"
Grid.ColumnSpan="6" Grid.RowSpan="3" >
</Border>
<Viewbox Grid.Row="0" >
<Image Name="img_ItemImage"
Source="{Binding Image, Mode=TwoWay }"
Width="20" Height=" 25" />
</Viewbox>
<Viewbox Grid.Column="2" Grid.ColumnSpan="3" VerticalAlignment="Top" >
<TextBlock Name="lbl_ItemName" TextWrapping="Wrap" Width="180" Foreground="Gray"
Text="{Binding Name , Mode=TwoWay }" >
</TextBlock>
</Viewbox>
<Viewbox Grid.Row="1" Margin="10,0" VerticalAlignment="Top" >
<TextBlock Foreground="Gray" >Qty:</TextBlock>
</Viewbox>
<Viewbox Grid.Row="2" Margin="0,0" VerticalAlignment="Top" >
<StackPanel Orientation="Horizontal" >
<Button Name="btn_Minus" FontWeight="ExtraBold" Tag="{Binding SKU_No,Mode=TwoWay}" Padding="0" Width="12"
Resources="{StaticResource cartitembutton}" Click="btn_Minus_Click" >
<Image Source="/Resources\Icons\minus.png" ></Image>
</Button>
<Border BorderThickness="1" Margin="2,0" Width="13" CornerRadius="2" BorderBrush="LightGray" >
<TextBlock Name="lbl_Quantity" FontWeight="Bold" Foreground="Gray"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Quantity , Mode=TwoWay }" >
</TextBlock>
</Border>
<Button Name="btn_Increment" FontWeight="ExtraBold" Width="12"
Resources="{StaticResource cartitembutton}" Tag="{Binding SKU_No,Mode=TwoWay}"
Padding="0"
Click="btn_Increment_Click">
<Image Source="/Resources\Icons\union_10.png" ></Image>
</Button>
</StackPanel>
</Viewbox>
<Viewbox Grid.Row="1" Grid.Column="2" Margin="5,0"
HorizontalAlignment="Left" Grid.ColumnSpan="3" >
<TextBlock Name="lbl_Price" FontWeight="DemiBold"
Text="{Binding Price , Mode=TwoWay}" ></TextBlock>
</Viewbox>
<Viewbox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="3"
VerticalAlignment="Top" Margin="0,0" >
<TextBlock Name="lbl_Appearence"
Text="{Binding Appearance , Mode=TwoWay }"
TextWrapping="Wrap" Foreground="Gray" Width="210" >
</TextBlock>
</Viewbox>
<Viewbox Grid.Column="5" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="2,2"
>
<Button Name="btn_DeleteItem"
Click="btn_DeleteItem_Click"
Resources="{StaticResource cartitembutton}" >
<Image Source="/Resources/Icons/delete.png" ></Image>
</Button>
</Viewbox>
</Grid>
</Viewbox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is how a listVeiw looks like.
You don't actually want the selected item, you want to know which item contained the button that was clicked- whether that item is selected or not.
You can do this with events, but the more "correct" way to do it in WPF is with commands.
Commands are a pattern which separate the logic of an action (e.g. deleting an item) from the visual component that triggers the action (e.g. the button the user clicks). A command includes a parameter, which you can use to specify which item the command is being executed on. There are a couple different types on commands in WPF, but I'll be explaining using RoutedCommand.
In your case you'd first declare your command(s) in your Window:
public static readonly RoutedCommand DeleteItemCommand =
new RoutedCommand("DeleteItem", typeof(MainWindow));
private void OnCanExecuteDeleteItem(object sender , CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
}
private void OnExecuteDeleteItem(object sender, ExecutedRoutedEventArgs e)
{
SomeType item = (SomeType)e.Parameter;
//Actually delete the item
}
And you'd add a CommandBinding to your Window which links the command to the methods which handle it:
<Window.CommandBindings>
<CommandBinding Command="local:MainWindow.DeleteItemCommand" CanExecute="OnCanExecuteDeleteItem" Executed="OnExecuteDeleteItem"/>
</Window.CommandBindings>
And finally, to link your delete Button to the command:
<Button Name="btn_DeleteItem" Resources="{StaticResource cartitembutton}" Command="local:MainWindow.DeleteItemCommand" CommandParameter="{Binding}">
<Image Source="/Resources/Icons/delete.png"/>
</Button>
CommandParameter="{Binding}" works because your Button is inside a DataTemplate, so its DataContext will be the item that is being displayed. This lets you check e.Parameter in your routed event methods to see which item is being interacted with.

UWP TabView OneWay x:Bind does not update

I have a TabView whose ItemTemplate is like this:
<controls:TabView.ItemTemplate>
<DataTemplate x:DataType="data:Playlist">
<local:HeaderedPlaylistControl
IsPlaylist="True"
Loaded="HeaderedPlaylistControl_Loaded"
MusicCollection="{x:Bind Mode=OneWay}" />
</DataTemplate>
</controls:TabView.ItemTemplate>
This is part of the HeaderedPlaylistControl:
<local:PlaylistControl
AllowReorder="False"
AlternatingRowColor="True"
ItemsSource="{x:Bind MusicCollection.Songs, Mode=OneWay}">
<local:PlaylistControl.Header>
<controls:ScrollHeader Mode="Sticky">
<UserControl>
<Grid
x:Name="PlaylistInfoGrid"
Padding="10"
Background="{ThemeResource SystemColorHighlightColor}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image
x:Name="PlaylistCover"
Grid.RowSpan="3"
Width="180"
Height="180"
Margin="20"
Source="Assets/monotone_bg_wide.png" />
<TextBlock
x:Name="PlaylistNameTextBlock"
Grid.Column="1"
Margin="0,5"
VerticalAlignment="Center"
FontSize="36"
Foreground="White"
Style="{StaticResource HeaderTextBlockStyle}"
Text="{x:Bind MusicCollection.Name, Mode=OneWay}" />
<TextBlock
x:Name="PlaylistInfoTextBlock"
Grid.Row="1"
Grid.Column="1"
Margin="0,5"
VerticalAlignment="Top"
Foreground="White"
Text="{x:Bind MusicCollection.Songs, Converter={StaticResource SongCountConverter}, Mode=OneWay}" />
</Grid>
</UserControl>
</controls:ScrollHeader>
</local:PlaylistControl.Header>
</local:PlaylistControl>
When I switch between tabs, the HeaderedPlaylistControl doesn't update it's content. Why is that?
Is it because of the MusicCollection property (it is of type Playlist) doesn't notify the binding when switching tabs? If so, where should I put the notification? The definition of Playlist is here.
HeaderedPlaylistControl is here:
Yes, as you suspected, the problem is that the MusicCollection property is an ordinary property which does not notify about changes. To make your code work, you need to make the MusicCollection property a dependency property (see docs). This is a kind of properties which are best for data-bound properties of visual controls and have many additional features as well.
public static readonly DependencyProperty MusicCollectionProperty =
DependencyProperty.Register(
nameof(MusicCollection), typeof(Playlist),
typeof(HeaderedPlaylistControl), null
);
public Playlist MusicCollection
{
get { return (bool)GetValue(MusicCollectionProperty); }
set { SetValue(MusicCollectionProperty, value); }
}

C# - Adding XAML elements to UWP app via x:Bind

Context: I'm writing a UWP Twitter client.
One of the useful bits of data Twitter returns via its API are objects for content that can be linked directly in a tweet - #hashtags, #usernames, $symbols, and URLs. This makes it easy to extract these objects from the string containing a tweet's full text, in order to turn them into links.
I understand how the XAML needs to look for this, with <run> and <hyperlink> tags, and I've figured out how to create that XAML dynamically for each tweet object.
What I can't figure out is how to inject my generated XAML into my app's DataTemplate. Because tweet content needs to be displayed on multiple pages in the app, I'm using a ResourceDictionary to hold all my XAML styling, including my DataTemplate. So, I'm entirely unsure how to connect my generated XAML to my app's UI.
For example, if a tweet looks like this:
"Hey #twitter, you're a time waster! #FridayFeeling"
My generated XAML objects look like this:
<Run>Hey </Run>
<Hyperlink link="http://twitter.com/twitter/">#twitter</Hyperlink>
<Run>, you're a time waster! </Run>
<Hyperlink link="http://twitter.com/search?hashtag=FridayFeeling">#FridayFeeling</Hyperlink>
If there's nothing to link in a tweet's text, then I can just use Tweet.Text as-is, so I'm trying to bind this to a TextBox. How can I handle inserting this XAML dynamically?
Am I stuck abandoning data binding entirely and looping through my collection to programmatically add all my XAML?
Here's my DataTemplate:
<DataTemplate x:Key="TweetTemplate" x:DataType="tweeter:Tweet2">
<Grid Style="{StaticResource ListItemStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" x:Name="RetweetedBy" x:Load="{x:Bind IsRetweet}" Height="28">
<StackPanel Orientation="Horizontal" Padding="4 8 4 0">
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
</Style>
</StackPanel.Resources>
<Border Height="28">
<TextBlock Height="24" FontFamily="{StaticResource FontAwesome}" xml:space="preserve"><Run Text=" "/></TextBlock>
</Border>
<TextBlock Text="{x:Bind Path=User.Name}" />
<TextBlock Text=" retweeted"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<StackPanel Orientation="Horizontal" Padding="5">
<TextBlock Text="{x:Bind Path=Tweet.User.Name}" Margin="0 0 8 0" FontWeight="Bold" />
<TextBlock Text="{x:Bind Path=Tweet.User.ScreenName, Converter={StaticResource GetHandle}}" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
<TextBlock Text="⦁" Margin="8 0" />
<TextBlock Text="{x:Bind Path=Tweet.CreationDate, Converter={StaticResource FormatDate}}" />
</StackPanel>
</Grid>
<Grid Grid.Row="2">
<TextBlock Text="***this is where I'm having problems***" Padding="5" TextWrapping="WrapWholeWords"/>
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*" MaxWidth="100"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Button x:Name="cmdComment" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="1">
<Button x:Name="cmdRetweet" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="2">
<Button x:Name="cmdLike" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="3">
<Button x:Name="cmdMessage" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
</Grid>
</Grid>
</DataTemplate>
If you want to use attached property, here is an example to start with :
public static class Twitter
{
public static readonly DependencyProperty InlinesProperty = DependencyProperty.RegisterAttached(
"Inlines", typeof(ICollection<Inline>), typeof(Twitter), new PropertyMetadata(default(ICollection<Inline>), PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBlock tb)) return;
tb.Inlines.Clear();
if (!(e.NewValue is ICollection<Inline> inlines)) return;
foreach (var inline in inlines)
{
tb.Inlines.Add(inline);
}
}
public static void SetInlines(DependencyObject element, ICollection<Inline> value)
{
element.SetValue(InlinesProperty, value);
}
public static ICollection<Inline> GetInlines(DependencyObject element)
{
return (ICollection<Inline>) element.GetValue(InlinesProperty);
}
}
And in xaml :
<TextBlock local:Twitter.Inlines ="{x:Bind TwitterData}"></TextBlock>
Where TwitterData is a List<Inline>

Formatting of text in a textblock in windows phone 7

I am have a text which is has bold, underline and italic html characters. For example
<b> hello<b> how are <i>you</i>. I am <u>fine</u>
I have to show it in formatted form in a textblock on WP7. I have a listbox like this
<ListBox x:Name="LBayaDetail" Loaded="LBayaDetail_Loaded" Margin="6,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="ayaContent" Margin="0,6,0,0" Hold="ayaContent_Hold" Tap="ayaContent_Tap" Loaded="ayaContent_Loaded" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="6"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="6" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Background="#FFC5AC88" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="ayaIndex" Text="{Binding aya}" FontSize="36" Margin="0" FontWeight="Bold" HorizontalAlignment="Center" />
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Center">
<Image Source="{Binding BookmarkImage}" HorizontalAlignment="Center" Width="48" Height="48" Margin="0,0,0,12" />
<Image Source="{Binding NoteImage}" HorizontalAlignment="Center" Width="48" Height="48" Margin="0,0,0,12" />
<Image Source="{Binding TagImage}" HorizontalAlignment="Center" Width="48" Height="48" Margin="0,0,0,12" />
</StackPanel>
</Grid>
<Grid Grid.Row="1" Background="#FFC5AC88" x:Name="Media" Tap="Media_Tap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image Source="/Images/Media-Play(1).png" Width="30" Height="30" HorizontalAlignment="Center" Margin="12,0,0,0" VerticalAlignment="Top" />
</Grid>
<!--ini pak dimana tempat untuk ayat dan translasi-->
<Grid Grid.Column="2" Background="#FFAC9574" Margin="6,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="aya" TextWrapping="Wrap" Text="{Binding text}" HorizontalAlignment="Right" FontFamily="/Fonts/me_quran2.ttf#me_quran2" FontSize="{Binding FontSizeAya}" Foreground="Black" Margin="24,0,12,-12" TextAlignment="Right" Visibility="{Binding visibility1}" />
</Grid>
<Grid Grid.Column="2" Grid.Row="1" Margin="6,0,0,0" Background="#FFAC9574" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel>
<TextBlock Visibility="{Binding visibility2}" x:Name="translation" Text="{Binding translation}" TextWrapping="Wrap" HorizontalAlignment="Right" FontFamily="/Fonts/ARIALUNI.TTF#Arial Unicode MS" FontSize="{Binding FontSizeTranslation}" Foreground="#FF5D2A07" Margin="12,6,6,0" />
<TextBlock Visibility="{Binding visibility3}" x:Name="translation2" Text="{Binding translation2}" TextWrapping="Wrap" HorizontalAlignment="Right" FontFamily="/Fonts/ARIALUNI.TTF#Arial Unicode MS" FontSize="{Binding FontSizeTranslation}" Foreground="DarkGreen" Margin="12,20,6,0" />
</StackPanel>
</Grid>
<!-- -->
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I fetch from database like
App.Listxyz = (Application.Current as App).db.SelectList<Aya>(strSelect);
And assign it to Listbox like this
LBayaDetail.ItemsSource = App.ListAyaBySurah;
And shows the text as it is and do not format it which is obvious. I searched for it and I was able to format individual textblock by using "RUN" but I am unable to do it in listbox.
I also tried to use HTMLTextBlock but it also doesn't format the text and shows it like this
Hi
How
Are
You
Any help will be much appreciated that how do I format a textblock with different text decorations.
Thanks
You should place a grid and a stackpanel inside the listbox. Something like the following
<Grid>
<StackPanel Grid.Column="1">
<TextBlock Padding="0,5,0,2" TextWrapping="Wrap">
<Run Text="{Binding test}" FontWeight="Bold" /> <Run Text="{Binding test2}" />
<LineBreak/>
<Run Text="{Binding test3}" />
</TextBlock>
</StackPanel>
</Grid>
One way to do that is:
public class FormattedText
{
public string Text { get; set; }
public bool IsBold { get; set; }
public bool IsItalic { get; set; }
public bool IsUnderlined { get; set; }
}
Have a method that converts the HTML you stored in your db to a list of the class you have above
example:
From this:
<b> hello<b> how are <i>you</i>. I am <u>fine</u>
to this:
First element:
Text = "hello"
IsBold = true
skip what not needed since bool default value is false
Second element
Text =" how are"
skip what not needed since bool default value is false
Third item
Text ="you"
IsItalic=true;
skip what not needed since bool default value is false
and so on....
and then have another method that from that list creates a list of Runs to be added to your TextBlock or
maybe create a custom TextBlock witch take the List<FormattedText> from DataContext and process it by adding the Run elements to self

Categories