How can I hide a Paragraph in a FlowDocument? - wpf

Is there any way to use databinding to show or hide a Paragraph within a FlowDocument? (I want to use MVVM, but with a FlowDocument as my view.)
Paragraph doesn't have a Visibility property. I'm not sure what else to look for.

I tried Chris Bova's answer, but it had a couple problems:
Text selection didn't work right
The text inside didn't flow like a paragraph
My solution was to add and remove the paragraph from the flow document.
The steps are:
Name the flow document (ie flowDocument)
Name the item before the paragraph you want to hide (ie previousBlock)
Name the paragraph you want to hide (ie hideParagraph)
Then:
if (<hide paragraph>)
{
if (previousBlock.NextBlock == hideParagraph)
{
flowDocument.Blocks.Remove(hideParagraph);
}
}
else
{
if (previousBlock.NextBlock != hideParagraph)
{
flowDocument.Blocks.InsertAfter(previousBlock, hideParagraph);
}
}

I had the exact same problem and handled it successfully by wrapping the content of the ListItem in a InlineUIContainer, like so:
<ListItem>
<Paragraph>
<InlineUIContainer>
<TextBlock x:Name="HideMe" Visibility="Collapsed">
<Hyperlink NavigateUri="...">Components</Hyperlink>
</TextBlock>
</InlineUIContainer>
</Paragraph>
</ListItem>
From here you can set the visbility of "HideMe" in code or through a binding.

Options I can think of...
Hide the content of the paragraph (don't include the paragraph in your model)
Extend Paragraph (or one of its base classes) and provide a dependency property for IsVisible

Set fontsize to 0.004. You can use a style data trigger if necessary.

Related

Vertical alignment of Label inside TextBlock is wrong

In a WPF popup window that I display to the user I want to put a text that is bound to a variable inside a block of text.
I've tried to do so by putting a <Label> inside a <TextBlock>.
However, this leads to alignment problems, see markup and picture below.
I wonder how I can get the text in the Label to align vertically with the text in the TextBlock, or if there is a better solution?
I could put the entire text in a variable, but then I don't know how to get <Bold> formatting for part of the text.
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
VerticalAlignment="Top" Height="99" Width="339" Grid.RowSpan="3">
The user is <Bold>responsible</Bold> for
<Bold><Label Content="00" Padding="0"/></Bold> vehicles
</TextBlock>
You can use the Run inline element for data binding text.
Starting in the .NET Framework 4, the Text property of the Run object is a dependency property, which means that you can bind the Text property to a data source.
It also has properties for styling the text, like FontWeight, no need for <Bold> here.
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
VerticalAlignment="Top" Height="99" Width="339" Grid.RowSpan="3">
The user is <Bold>responsible</Bold> for
<Run Text="{Binding YourProperty}" FontWeight="Bold"/> vehicles
</TextBlock>
The result looks like this:
As a general note on the issue: The elements inside TextBlock should be inline elements. Here is an article that has links to other inline elements that could be useful to you, like span that allows for grouping other inline elements and applying styles or to them.
How to: Manipulate Flow Content Elements through the Inlines Property
WPF has two fundamental base types, UIElement and ContentElement. While a TextBlock and Label are UIElements, the content of TextBlock are inlines, which are ContentElements. That is why the alignment is off, they serve very different purposes. You can read up more on the differences and concepts here:
Base Element APIs in WPF Classes
UIElement
UIElement is a base class for WPF core level implementations building on Windows Presentation Foundation (WPF) elements and basic presentation characteristics.
ContentElement
Provides a WPF core-level base class for content elements. Content elements are designed for flow-style presentation, using an intuitive markup-oriented layout model and a deliberately simple object model.
Flow Document Overview

wpf - how to keep a control from being selected through tabbing [duplicate]

How do I set tab ordering in WPF? I have an ItemsControl with some items expanded and some collapsed and would like to skip the collapsed ones when I'm tabbing.
Any ideas?
If you want to explicitly set the tab ordering for elements in your form, the following attached property is supposed to help:
<Control KeyboardNavigation.TabIndex="0" ... />
I say "supposed to help" as I haven't found it very reliable though I probably need to read more about how it is intended to be used. I only post this half baked answer because no one else mentioned this property.
Note that in Win RT, the property is just TabIndex="0".
You can skip elements in the tab sequence by setting KeyboardNavigation.IsTabStop on the element in XAML.
KeyboardNavigation.IsTabStop="False"
You can setup a trigger that would toggle this property based on the expanded state.
<Control KeyboardNavigation.TabIndex="0" ... /> Works perfectly fine...
For example-
<ComboBox Height="23"
Margin="148,24,78,0"
Name="comboBoxDataSet"
VerticalAlignment="Top"
SelectionChanged="comboBoxDestMarketDataSet_SelectionChanged"
DropDownOpened="comboBoxDestMarketDataSet_DropDownOpened"
KeyboardNavigation.TabIndex="0" />
<ComboBox Height="23"
Margin="148,56,78,0"
Name="comboBoxCategory"
VerticalAlignment="Top"
SelectionChanged="comboBoxDestCategory_SelectionChanged"
DropDownOpened="comboBoxDestCategory_DropDownOpened"
KeyboardNavigation.TabIndex="1" />
Will allow you to navigate through these two combo boxes using TAB key.
I think there is a much easier solution here,
at the top within your control or window or whatever, you could add:
KeyboardNavigation.TabNavigation="Cycle"
This also automaticaly ignores the collapsed tabs.
Another alternative that has worked for me in the past is to simply remove all explicit TabIndex statements, and let the controls use the order that they're declared in XAML work their magic.
This, of course, may require you to reorder your controls. But this is a simple copy-paste operation.
You can use KeyboardNavigation.TabNavigation="None" to completely skip the Tabbing for specific control.

Make a silverlight textblock act like a hyperlink

I'm pretty new to silverlight. I have a text block that is displayed inside a datagrid
(inside a DataGridTemplateColumn.CellTemplate template to be precise).
I'd like to dynamically make some of the textblocks into hyperlinks that open a new window.
Is there a way to do this - so far all I can come up with is using a hyperlink button and trying to style it to look like a text block.
Any help would be very much appreciated.
HyperlinkButton is a ContentControl so it can actually take some kind of pre-styled TextBlock (or other control) as it's content (instead of just using a simple string as Content).
<HyperlinkButton NavigateUri="http://myurl.com">
<TextBlock Text="My Link Text" Foreground="Black" />
</HyperlinkButton>
You would have to use a custom HyperlinkButton template if you wanted to style it to get rid of the default teal colored focus ring, etc. You could also set the IsEnabled property of the HyperlinkButton to false to prevent link behavior on any cells that weren't actually links if you are trying to set them up in some dynamic way.

WPF Styles Question

A simple question which I can't find the answer on the web for some reason...
I want to place the content to a ResourceDictionary:
<TextBlock
Style="{StaticResource HomePageTextStyle}">
<LineBreak/>
Hello<LineBreak/>
<Bold>World!</Bold>
<LineBreak/>
</TextBlock>
The best I could do was:
<s:String x:Key="HomePageTextContent">
Hello World!
</s:String>
Which stripped all the formatting from the content :( Help please~ Thanks in advance. Oh, and If you can recommend a nice reference for using WPF Styles, it would be great~ Thanks!
I'd say you want to use data-binding instead of applying a style, since you are putting content in the TextBlock not changing the appearance of the TextBlock itself, e.g. drawing a border around it.
According to MSDN: TextBlock supports the hosting and display of Inline flow content elements. To be more precise, the content of the TextBlock in your first code block becomes a InlineCollection in the Inlines property of the TextBlock. Unfortunately the Inlines property isn't a dependency property so we can't bind data to it. The Text property, on the other hand, is a dependency property but doesn't allow anything other than a String.
To make a long story short, I don't think you can achieve what you want using pure XAML.

Is there an ItemsControl equivalent for text content?

I have some data that I want to present in a FlowDocument. This will basically be a view that explains the data in a friendly way, with section headers, paragraphs of text, etc., and which I will display in a FlowDocumentScrollViewer.
To this end, I would like to create a bulleted list (<List>) out of the contents of an ObservableCollection. I know how to do that with ItemsControl, but how do I do it for ListItem elements in a FlowDocument, since they're part of the TextElement class hierarchy rather than the Control hierarchy? Is there an equivalent of ItemsControl for text content inside a TextBlock or FlowDocument?
Edit: The article Sergey linked to is the perfect starting point. The only problem is that the article's code can only use a Section or a TableRowGroup as the items panel, and doesn't yet support using a <List>. But that was trivial to fix -- just a matter of adding this code at the end of ItemsContent.GenerateContent, just before the final else:
else if (panel is List)
((List) panel).ListItems.Add((ListItem) element);
What you are looking for is possible, but requires significant amount of coding. Fortunately, Vincent Van Den Berghe posted a nice article on the MSDN describing how to Create Flexible UIs With Flow Documents And Data Binding , including the code!
Instead of using a FlowDocument, you can use an ItemsControl and change the panel used to display items to a WrapPanel. This will allow you use the ItemsControl as you want, but change its display semantics to a WrapPanel (which I believe functions like a FlowDocument. You'd do it something like this:
<ItemsControl>
<ItemsControl.ItemsPanelTemplate>
<WrapPanel />
</ItemsControl.ItemsPanelTemplate>
</ItemsControl>
You can set any properties on the inner WrapPanel as you desire.
I think you are looking for the List element:
http://msdn.microsoft.com/en-us/library/system.windows.documents.list.aspx
Bubblewrap points out a few more details. You'd likely bind to the ListItems property and need to use a ValueConverter to convert your source list to a list of type ListItemsCollection.
Bubblewrap points out that this is readonly and that the ListItemsCollection has an internal constructor. So...
I think what you'd have to do is this:
<ContentControl Content="{Binding TheArrayOfText, Converter={StaticResource StringsToListConverter}" />
This is pretty unfortunate, but I think it would work. You'd have to write a converter to create a new List object and call .Add( on each item.

Resources