Making a data template - XAML - c#

I have a listbox I want to display information in, I bring in variables from a text file and assign them to strings. I want the end result to look like this:
"Make: " [Make] "\t" "Model: " [Model]
"Price: " [Price] "\t" "Mileage: " [Mileage]
I have read into the best options, I am using a ToString method at the moment, however I have read up that templates in the XAML would be a better option.
My question: How do I format a datatemplate in the XAML to display the above information and bring in the variables needed?

It'd look something like this:
<ListBox ItemsSource="{Binding MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="Make: "/>
<Run Text="{Binding Make}"/>
<Run Text="Model: "/>
<Run Text="{Binding Model}"/>
<Run Text="Price:" />
<Run Text="{Binding Price}"/>
<Run Text="Mileage:" />
<Run Text="{Binding Mileage}"/>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Assuming you have an observable collection of MyList built up from your file, which has properties of Make, Model, etc.
Given your structure here, you may want to consider a ListView (like a list but with columns) rather than a list.

Related

Getting digits after decimal point

I'm binding an SqlMoney type to a TextBox in WPF and I'm trying to put digits after decimal point into superscript. This is what I've got so far:
<TextBlock>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26">00</Run>
</TextBlock>
Is there a simple way to this in WPF using something like StringFormat or I need to split it somewhere else in code and then bind?
Edit:
Ok, I might have explained it badly. This is actual implementation in code right now:
Model property
public SqlMoney Price { get; }
View
<TextBlock Text="{Binding Mode=OneWay, Path=Price}" />
Effect:
Effect - before and after
Is there way to make View handle splitting or I need to change implementation in Model or VM?
When you use binding, you can use StringFormat to do what you need. In your example there is no binding so no place for StringFormat.
Here is a StringFormat you can use when binding:
StringFormat={}{0:00.00}
Example of binding with StringFormat (assuming Superscript is a property of you DataContext):
<TextBlock>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26" Text="{Binding Superscript, StringFormat={}{0:00.00}}"/>
</TextBlock>
If you don't have yet the DataContext set up and you want a self contained example you could create a Resource and bind to it:
<TextBlock>
<TextBlock.Resources>
<sys:Double x:Key="Superscript">0</sys:Double>
</TextBlock.Resources>
<Run FontSize="50">1000</Run>
<Run BaselineAlignment="TextTop" TextDecorations="Underline" FontSize="26" Text="{Binding Source={StaticResource Superscript}, StringFormat={}{0:00.00}, Mode=OneWay}"/>
</TextBlock>
In this example I had to use OneWay binding because I'm binding to a static resource.
Result:

TextBlock TextWrapping Wrap and NoWrap combined and Text through DynamicResource

I have got multiple TextBlocks whose Text is inserted through DynamicResource. They are all set to TextWrapping="Wrap". But inside those Text-strings I have words which are not allowed to be split up. Those words must be kept as a whole word.
With hardcoded Text in Xaml it's quite easy solved via a TextBlock inside a Textblock:
<TextBlock TextWrapping="Wrap">
Example text with wrap and <TextBlock TextWrapping="NoWrap" Text=" example text without wrap"/
</TextBlock>
But this solution does not work when Text the is inserted through DynamicResource, because the text is not getting parsed.
How can I combine nowrap and wrap inside a DynamicResource Text without splitting it into multiple TextBlocks one after another?
PS: I have now created an example to demonstrate the behavior I would like (green) and the failed attempts (red, orange, darkred) of solving it:
<StackPanel HorizontalAlignment="Center" Width="80" Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Foreground="green">
bla1 bla2 bla3 bla4 <TextBlock TextWrapping="NoWrap" Text="Together(en)"/> bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="Wrap" Foreground="red">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="Wrap" Foreground="orange">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
<TextBlock TextWrapping="WrapWithOverflow" Foreground="DarkRed">
bla1 bla2 bla3 bla4 Together(en) bla5 bla6 longWordWhichShouldBreak
</TextBlock>
</StackPanel>
Use NO-BREAK SPACE in your dynamic text. For example:
<TextBlock TextWrapping="Wrap">
Example text with wrap and example text without wrap
</TextBlock>
You can replace space with this char in those parts that you need this behaviour:
Replace(" ", System.Convert.ToChar(160))
Have you considered using 'WrapWithOverflow' instead of 'Wrap'?
This will only break the line if a space appears.
You can then set the words that must appear together with dashes,e.g.-
'regular line and words-that-shouldn't-break'
You should use Run:
<TextBlock>
<Run Text={x:static SomeText} />
<Run Text={x:static SomeNoWrapText}
TextWrapping="NoWrap"/>
<Run Text={x:static SomeMoreText} />
</TextBlock>
It's a bit much for a comment, but also not a complete answer.
Lets translate your example piece of XAML from all the implicit contents to a full qualified structure.
Your simplified XAML, using the implicit content properties and so on:
<TextBlock TextWrapping="Wrap" Foreground="green">
bla1 bla2 bla3 bla4 <TextBlock TextWrapping="NoWrap" Text="Together(en)"/> bla5 bla6 longWordWhichShouldBreak
</TextBlock>
Equivalent actual structure:
<TextBlock TextWrapping="Wrap" Foreground="green">
<TextBlock.Inlines>
<Run Text="bla1 bla2 bla3 bla4 "/>
<InlineUIContainer>
<InlineUIContainer.Child>
<TextBlock TextWrapping="NoWrap" Text="Together(en)"/>
</InlineUIContainer.Child>
</InlineUIContainer>
<Run Text=" bla5 bla6 longWordWhichShouldBreak"/>
</TextBlock.Inlines>
</TextBlock>
This should give you some idea about the complexity of what you have in your XAML. You can't archieve the same result by simply setting the Text property.
Currently I can't answer how to solve this issue, since DynamicResource is not enough information to start transforming into above structure.
You may want to have a look at this question: Data binding the TextBlock.Inlines

How to handle subtext Tap?

In Windows Phone (on both Windows Phone 7.1 and Windows Phone 8), in a block of text with wrapping I want a subtext to be underlined and clickable. However, Runs in TextBlock/RichTextBox don't have any events. Using WrapPanel of WPToolkit I could achieve the desired wrapping by putting each words in a separate TextBlock, but i loose the ability to set TextAlignment to Justify. Is there a better way to do this?
<TextBlock TextWrapping="Wrap">
<Run Text="I have a paragraph consisting of multiple lines that I want to be neatly wrapped with just one word that I'll be able to "/>
<Run TextDecorations="Underline">tap</Run>
</TextBlock>
<toolkit:WrapPanel>
<TextBlock Text="I "/>
<TextBlock Text="have "/>
<TextBlock Text="a paragraph "/>
<TextBlock Text="consisting "/>
...
<TextBlock Text="able to"/>
<TextBlock TextDecorations="Underline" Tap="HandleLinkTap" Text="tap"/>
</toolkit:WrapPanel>
Does https://stackoverflow.com/a/15148602/546896 solves your problem?
I know little hackish way but still see if it works.
<RichTextBox TextWrapping="Wrap">
<Paragraph>
<Run Text="I have a paragraph consisting of multiple lines that I want to be neatly wrapped with just one word that I'll be able to " />
<Hyperlink Click="HandleLinkTap">Tap</Hyperlink>
</Paragraph>
</RichTextBox>

RichTextBox with variable number of bound runs

I was working on a project recently where I feel a nice solution would be to display a paragraph in a RichTextBox that is bound to a collection of objects that will hold a string and a few properties about that string. I was hoping I could do something like this:
<RichTextBox Name="rtb" IsReadOnly="True" FontSize="14" FontFamily="Courier New">
<FlowDocument>
<Paragraph>
<Run Foreground="Red" Text="{Binding foo}"/>
<Run Foreground="Green" Text="{Binding bar}"/>
<Run Foreground="Blue" Text="{Binding baz}"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
This works fine, however this is defining all the bindings ahead of time, but I actually won't know them until run time, each string will be stored into a collection. I was trying to think of a way to define and bind multiple Run blocks and place them all in the RichTextBox to be displayed. I would prefer a primarily xaml solution if possible, but if I must do it in the code behind that may be OK as well as long as the bindings stick and everything updates properly after the initial load.
I tried something like this, but was having trouble figuring how how to bind to the Text property of a Run from the code behind:
foreach (var item in col)
{
Run run = new Run();
Binding b = new Binding();
b.Source = this;
b.Path = new PropertyPath(item.StaticText);
run.SetBinding(run.Text, b); //Tells me Text is not a dependency property
//But it could be bound if this were xaml?
}
I also tried putting an ItemsControl inside the RichTextBox that had Run as the data template of the items, but it wouldn't allow me to make the data template a Run tag, and I'm not sure that would have worked anywway.
Any guidance on the best approach, or what's wrong with my solution.
You could use this...
<Paragraph>
<ItemsControl ItemsSource="{Binding MyRuns}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Foreground="{Binding Color}" Text="{Binding Text}"/>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate >
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!--<Run Foreground="Red" Text="{Binding foo}"/>
<Run Foreground="Green" Text="{Binding bar}"/>
<Run Foreground="Blue" Text="{Binding baz}"/>-->
</Paragraph>
And define MyRuns as a collection on your view model, e.g.
public ObservableCollection<RunData> MyRuns { get; set; }
Put properties in your RunData etc.
And you can of course remove ItemsControl.ItemsPanel, that's just for fun
This seems to have gotten the job done for me, I created an ItemsControl that used a WrapPanel as the ItemsPanel. Then I can bind each item to my collection of strings and it comes out looking like a nice paragraph of variable strings. I'll keep the question open though in case someone comes up with a more elegant solution.
<RichTextBox Name="rtb" IsReadOnly="True">
<FlowDocument>
<Paragraph>
<ItemsControl ItemsSource="{Binding col}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding StaticText,
UpdateSourceTrigger=PropertyChanged}"/><TextBlock Text=" "/>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Paragraph>
</FlowDocument>
</RichTextBox>

How to bind array to Data template - List Box

I am currently parsing an HTML to produce an array shown below in a listbox
I am outputing each object in the array to a textbox like so
//first line
flight1.Text = node[0][2];
origin1.Text = node[0][3];
status1.Text = node[0][7];
time1.Text = node[0][6];
//second line
textBlock1.Text = node[1][3];
textBlock2.Text = node[1][3];
textBlock4.Text = node[1][7];
textBlock3.Text = node[1][6];
This is the outcome
AS you can image this is fairly grueling work and probably not the best way to do it.
Is there anyway to Bind each section on the array eg.. all flight names to a listbox in a data template so it would automatically list all the flight times and all the flight times etc..
Something like this for the XAML
<ListBox Margin="6,6,-12,0" Name="listBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="Auto">
<TextBlock Text="{Binding FlightNumber}" Foreground="#FF4BCCF5" FontSize="24" />
<TextBlock Text="{Binding Origin}" TextWrapping="Wrap" FontSize="22" Foreground="#FF969696" />
<TextBlock Text="{Binding Time}" TextWrapping="Wrap" FontSize="20" Foreground="#FF05C16C" />
<TextBlock Text="{Binding Status}" TextWrapping="Wrap" FontSize="20" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm not sure what you would like to achieve. But in general I would suggest to do the following steps:
Parse the HTML
Put each line in FlightInformation-Class (with properties like you have in your XAML-example)
Put all the FlightInformation-Objects in an ObservableCollection
Apply a DataTemplate to your ItemsControl

Categories

Resources