Making clickable URLs in RichTextBox using bindings - c#

My XAML has a DataTemplate defined which has ItemsSource set to some data class, which holds properties that will be presented in UI. One property is "Files", which has to display one or more files in the form of <Hyperlink NavigateUri="URLtoFILE">Filename</Hyperlink> (optional filesize).
The property is currently of type string where I'm concatenating different files' URLs and text together. But the stuff I put into that property display on screen verbatim.
I've seen this: WP8: RichTextBox has no Document property, but I have the problem of using data templates and bindings, which makes referencing the RichTextBox object in code impossible (is it?).
How can I mix text and clickable URLs within a WP8 control that is using data templates and bindings?
EDIT: If it helps, the ItemsSource always holds only one object.
EDIT: Part of XAML
<Grid>
<phone:LongListSelector x:Name="List">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<RichTextBox IsReadOnly="True">
</RichTextBox>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>

You want to show a list of urls?
If you want this :
<lisbox itemSource={Binding YourItemSource} selectedItem="{Binding ItemProperty}">
<listbox.ItemTemplate>
<dataTemplate>
<textblock>
<Hyperlink Command="{Binding HyperLinkTapped}" NavigateUri="URLtoFILE"></Hyperlink>
</textblock><
</datatemplate>
</listbox.itemtemplate>
</listbox>

Related

Auto-scroll Listbox based on TextBox text

In WPF and MVVM pattern, I have a TextBox and a ListBox. The ListBox is bound to a collection of items using a DataTemplate. The default count for this collection is about 50 or so.
What I wanted to achieve is a filter-like action. If it's possible, I wouldn't like to change the list view or anything like that, but simply to scroll to the item corresponding to the TextBox match, preferably without selecting it.
I've seen some examples and solutions using CollectionView and Filter (couldn't get it to work btw), and some using auto-scroll to the end of the list or to a new added item, but none specific to my case.
My Listbox is structured as follows:
<ListBox IsTextSearchEnabled="True" HorizontalAlignment="Stretch" Margin="6,49,0,0" Name="lbObjectA" VerticalAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type src:Dto}">
<StackPanel Height="20" Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" Margin="0,3,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

How to bind to a source inside a ListBox different from the ItemsSource already specified

I have a ListBox inside a HubSection, whose Items are bound to a class "players" added to my DefaulViewModel via code behind.
First I simply put a TextBox bound to the property "PlayerName" of my class "players".
Now I would like to add a ComboBox with some items that are NOT part of the class players.
Is it possible ? I thought that definind an ItemsSource in the ComboBox would sort of override the ItemsSource of the ListBox, but nothing displays.
The DataContext of the whole page is defined like so:
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
Then the HubSection is like so:
<HubSection x:Name="HubSec1">
<DataTemplate>
<ListBox x:Name="ListBox1" ItemsSource="{Binding players}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=PlayerName, Mode=TwoWay}"/>
<ComboBox ItemsSource="{Binding Path=ListOfElements}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</HubSection>
If I define the ComboBox in the same way but outside the ListBox, it will display the string elements of "ListOfElements" properly.
But in this ListBox, the ComboBox is empty. So my guess is that having defined an ItemsSource for the ListBox, it is not possible to override it.
I have tried to define a DataTemplate but was not successful doing so, but it might be the good solution (and I did not proceed properly)
What am I missing ?
Edit :
The ComboBox items is an ObservableCollection. It is not part of the "players" class.
Here is how I added these elements to the DefaultViewModel
DefaultViewModel.Add("players", players);
DefaultViewModel.Add("MyItemsList", ListOfElements);
You can walk up the visual tree and bind to an ancestors datacontext:
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
EX:
{Binding Path=ListOfItems, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}
that should give you the datacontext that the listbox has, so assuming your ListOfItems exists in that data context.
Or you can name your control, and then bind to its datacontext by element name:
{Binding ElementName=mySourceElement,Path=ListOfItems}
It can be a little bit tricky to create a good working binding in Windows Apps. A widely used work around is to use the Tag property.
<ListBox x:Name="ListBox1" ItemsSource="{Binding players}" Margin="0,184,0,0" Tag="{Binding Path=ListOfElements}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=PlayerName, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Tag, ElementName=ListBox1}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A binding to an element wirh the specific name will work always. And the ListOfElements should be in the scope of the ListBox so you can use the Tag property as a proxy. If you need to bind more than one property, you can also use dummy XAML elements:
<Border Tag="{Binding ...}" Name="dummy1"/>

Display data from two levels down

I have the following classes, which contain ObservableCollections of the next level down:
Draw
ObservableCollection<Round>();
Round
ObservableCollection<Formation>();
Formation
So a Draw is made up of Rounds, Rounds are made up of Formations.
I have a page which has a button to create a random draw, I currently have it calling another class which returns a draw:
this.defaultViewModel[DrawName] = RandomDraw.generate();
I am having no problem binding a ListView to Rounds and displaying round information, but how do I display the individual formations? This is what I am currently doing, I was not expecting to be able to just display things by binding to Formations but how do I access it?
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<TextBlock
Text="{Binding Formations}"
TextWrapping="WrapWholeWords"
Pivot.SlideInAnimationGroup="2"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemContentTextBlockStyle}"
Margin="0,0,19,0"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You should take a look at Hierarchical Data Templates, which are used by the WPF TreeView control rather than ListViews. They are a natural fit to show hierarchical data. Of course, like any WPF control, you can completely customize their appearance using styling and templates. Here are some good references:
MSDN How to: Use a TreeView to Display Hierarchical Data
Hierarchical Databinding in WPF
However, if you would like to keep using ListViews, then one way to do this is to nest another container control inside the parent ListVIew. ObservableCollections are processed automatically by specific WPF elements, such as Panels. In your example, you can replace the second TextBlock with another ListView, with an ItemTemplate similar to the first. It can also be any Collection-like Panel element, such as StackPanel.
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<!-- CHANGED CODE HERE -->
<ListView
ItemsSource="{Binding Formations}"
...>
<ListView.ItemTemplate>...</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Optimal way to populate a large number of textboxes in MVVM

I'm currently creating a WPF application using MVVM. I have a large number of textboxes in a window (about 20) that need to be bound to specific elements in a list and need to be populated all at once. Normally I'd push them into an array and populate them that way but I can't do so without breaking the MVVM model. Is there a quick and efficient way I can do this while still adhering to MVVM?
You could bind your list to an ItemsControl and change it's item template to be a TextBox.
<ItemsControl ItemSource={Binding aList}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I don't see why strictly this would break MVVM, if instead of using an Array you used a List, put it in your ViewModel and then use indexed binding to bind to specific elements.
Something like:
<StackPanel>
<TextBox Text="{Binding MyViewModelList[0]}">
<TextBox Text="{Binding MyViewModelList[1]}">
<TextBox Text="{Binding MyViewModelList[2]}">
</StackPanel>
or if you want something more dynamic, instead of List, put an ObservableCollection in your VM, and bind to it in an ItemsControl with a DataTemplate.
<ItemsControl ItemsSource="{Binding Path=MyViewModelObsCol}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Syntax might not be 100% as I don't have an IDE to test, but something along these lines might be what you're after.
If you are trying to populate textbox on the bases of selection in list box try this
Another option is creating a COllection view source which i don't think you will require here

How to create ListBox.Itemtemplate,datatemplate programatically in Windows Phone 7

I find that there is some item templates, data templates and binding in the .xaml file for listbox. Is there any way to create it in code behind?
Is there any way to create data templates programataically?
this is the XAML CODE,BUT I need in code behind using c# not in XAML,because
am working in dynamic list box creation with adding itemtemplatem,datatemplate
<ListBox Height="520" HorizontalAlignment="Left" Margin="0,6,0,0" Name="lstimge" VerticalAlignment="Top" Width="450" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Width="150" Stretch="Uniform" HorizontalAlignment="Center" />
<TextBlock Text="{Binding FileName}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Kindly give the solution
Thanks,
Ashok
You can't build templates from code - this can only be done from XAML.
If you dynamically generated the template XAML in your code, you could load it as described here.
I suspect you'll find yourself opening a whole can of worms if you go down this route. As an alternative, you could predefine a set of templates, and choose the correct one dynamically at runtime, as described here
You could use XamlReader.Load to dynamically load XAML in code-behind and cast it to a DataTemplate, later assigning it to the ItemTemplate. Here is an example.
Is the DataTemplate that you want to use the same for all listboxes or is that also dynamically generated? If it is the same for all of them then you could save it as a Style in your Resources and then just create the Listbox object dynamically and apply the style.

Categories