WPF: PART_ContentHost not scrolling - c#

I am trying to make a Log area within my application and the customer has requested the ability to cut/paste the log messages from this area.
I originally was using the following to setup the log area with scrolling, but this does not allow the user to select & copy text:
<ScrollViewer DataContext="{StaticResource Log}"
Content="{Binding Appender.Notification}"
Height="150">
<ScrollViewer.Resources>
<Style TargetType="{x:Type ScrollViewer}">
<Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
</Style>
</ScrollViewer.Resources>
</ScrollViewer>
I found this solution to create a read only TextBox with select-able text:
<TextBox Name="LoggingTextBox"
Height="250"
Width="950"
DataContext="{StaticResource Log}"
Text="{Binding Appender.Notification}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="PART_ContentHost" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
This works to allow the selection of text within the log area but the scrolling does not work. I added the properties for *ScrollBarVisibility (not in the original solution).
How can I get the scrolling to work using this TextBox styling?

The fix is pretty simple: just change your Border to a ScrollViewer, and you will get the standard scrolling behavior for a TextBox.

Related

How do I remove the borders separating the headers in a Listview in XAML (WPF)?

I am making a ListView which loads users in from an Active Directory. To accomplish the brand/styling of the company I am developing the application for I would like to tweak some of the styling of the ListView element.
I have made it so the border of the headers in the Listview are transparent. In the editor in Visual Studio it looks how I want it to be, but when I look at the headers in the ListView in runtime I still get to see borders separating the headers (See image below).
https://i.gyazo.com/99dc8d60d6c5b2e1761456df685d850f.png
I have already tried Googling and I even went to the second page of the Google search result. Can you imagine?
Down here is the style I have used for the headers in my XAML file
<Style x:Key="ListViewHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
<Setter Property="IsHitTestVisible" Value="False"></Setter>
</Style>
What I want is to remove those borders separating the headers in my ListView element.
You can override the template of the GridViewColumnHeader
<Window.Resources>
<Style x:Key="GridHeader" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
<TextBlock Text="{TemplateBinding Content}" Padding="5"
Width="{TemplateBinding Width}" TextAlignment="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ListView>
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridHeader}">
</ListView.View>
</ListView>
Solution taken form here: Remove Separators in ListView Columns - WPF

WPF XAML display content in a ContentControl

I need to display a number in a square, centered horizontally and vertically.
When I tried to use a label for that purpose, it seemed like it ignored the centering completely. So I decided to use a grid and display a label on the grid as that centers perfectly.
I need to use a template as there's several themes available. From what I've found on the internet, I thought this ( ignoring the centering for now )
<ControlTemplate x:Key="ClockTemplate">
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Background" Value="White"/>
</Style>
</Grid.Style>
<Label>
<Label.Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="#376092"/>
</Style>
</Label.Style>
<ContentPresenter/>
</Label>
</Grid>
</ControlTemplate>
would be correct. Using it as follows:
<ContentControl Content="20" Height="64" Width="64" Template="{DynamicResource ClockTemplate}"/>
the content is not displayed tho, what am I doing wrong? Also, is there a better way to achieve my goal?
As per my understanding this is not the correct approach. Instead of creating ControlTemplate you have to write a Style for your control like below, also use StaticResource binding if possible. It is faster than Dynamic binding. Please not that, I have not mentioned the Label size inside the ControlTemplate. Please do it based on your needs
<Style x:Key="ContentControlStyle"
TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Background="White">
<Label Foreground="#376092"
Width="200"
Height="100" Content="{TemplateBinding Content}">
</Label>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
bind your ContentControl with the newly created Style like below
<ContentControl Style="{StaticResource ContentControlStyle} ">
If your requirement is only to set some value in ContentControl, use Label instead and change the Style of the Label. Because ContentControl is heavy

ContentControl Rotate decorator rendering

I have recently stumbled upon following issue: In my WPF application I've implemented a little designer, where you can put elements on canvas, move, scale and rotate them.
While searching the web I found following solution to this problem . This solution implements moving, scaling and rotating by System.Windows.Controls.Primitives.Thumb class so I thought I would just adjust this solution to my app and move on. The problem is, while on my machine everything is fine, on the others there are some rendering problems. I've made a screen shot of what I'm saying:
I'm using Windows 7 even though I run my app on other Windows 7 and it is also rendered wrong. I run my app with Windows XP and other compatibility settings on my machine but I wasn't able to reproduce this bug. What is this about and what am I possibly doing wrong?
This is my xaml file I'm using for content control styling:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:COMPANY.WPUI.LayoutDesignModel.Thumbs">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MoveThumb.xaml"/>
<ResourceDictionary Source="ResizeDecorator.xaml"/>
<ResourceDictionary Source="RotateDecorator.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="DesignerItemStyle" TargetType="ContentControl">
<Setter Property="MinHeight" Value="50"/>
<Setter Property="MinWidth" Value="50"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<Control Name="RotateDecorator" Template="{StaticResource RotateDecoratorTemplate}" Visibility="Collapsed"/>
<s:MoveThumb Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll"/>
<Control x:Name="ResizeDecorator" Template="{StaticResource ResizeDecoratorTemplate}" Visibility="Collapsed"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Setter TargetName="ResizeDecorator" Property="Visibility" Value="Visible"/>
<Setter TargetName="RotateDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
A this is RotateDecorator.xaml file that happens to cause problems:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:COMPANY.WPUI.LayoutDesignModel.Thumbs">
<Style TargetType="{x:Type s:RotateThumb}">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:RotateThumb}">
<Grid Width="30" Height="30">
<Ellipse Width="30" Height="30" Fill="#B0B0BB" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="RotateDecoratorTemplate" TargetType="{x:Type Control}">
<Grid>
<s:RotateThumb Margin="-18,-18,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<s:RotateThumb Margin="0,-18,-18,0" VerticalAlignment="Top" HorizontalAlignment="Right" />
<s:RotateThumb Margin="0,0,-18,-18" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
<s:RotateThumb Margin="-18,0,0,-18" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
</Grid>
</ControlTemplate>
</ResourceDictionary>
The first thing I think of whenever seeing something like this is the graphics cards. You can get some strange behaviors with certain graphics cards, especially if their drivers are not installed properly/up to date.
This is caused by MergedDictionaries. The Diagram Designer Project splits the Move, Resize, and Rotate actions into 3 separate dictionaries. From the screenshot you can see the resize thumb is loaded. In my case the move action also worked, but like the question the rotate thumbs weren't displayed. No errors were thrown, but examination with Snoop shows that it wasn't able to find the rotate dictionary.
This solution expands on what I've covered above: https://stackoverflow.com/a/17083360/978622
To solve: Combine the resource dictionaries into a single resource dictionary.

WPF: how to style a class like in css?

Let's say I have a UserControl with 4 Borders:
<Border />
<Border />
<Border />
<Border />
Now in my Resources I can go:
<Style TargetType="{x:Type Border}">
... change some properties here
</Style>
Now this is all good, but it will target all borders in my UserControl.
But what if I just want to target a subset of them?
I'd like to go:
<Border Class="Type1" />
<Border Class="Type1" />
<Border />
<Border />
And then go:
<Style TargetType="{x:Type Border}" TargetClass="Type1">
... change some properties here
</Style>
But this obviously doesn't exist, is there some other way I can achieve what I'm after?
Thanks
Though the syntax isn't quite as clean as in CSS, it is a lot more specific.
To build on your example, what you're looking for is:
<Border Style="{StaticResource Type1}" />
<Border Style="{StaticResource Type1}" />
<Border />
<Border />
And then go:
<Style TargetType="{x:Type Border}" x:Key="Type1">
... change some properties here
</Style>
Remember that WPF styles don't actually cascade like CSS does.
A more detailed styling reference:
https://web.archive.org/web/20141210000517/http://dotnetslackers.com/articles/wpf/StylesResourcesAndControlTemplatesInWPF.aspx
Something that I find most people are not aware of is WPF's ability to nest Styles within Style.Resources. For example:
<!-- Define a new style for Borders called InfoBox, that will have a red background,
and further override all buttons within it to have Yellow Text. An extra style,
"Strawberry" is also defined, that lets specific buttons be selected to be styled
as Green FG on DarkRed BG -->
<Style TargetType="{x:Type Border}" x:Key="InfoBox">
<Setter Property="Background" Value="Red"/>
<Style.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="DarkYellow"/>
</Style>
<Style TargetType="{x:Type Button}" x:Key="Strawberry">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="Background" Value="DarkRed"/>
</Style>
</Style.Resources>
</Style>
...
<Border Style="{DynamicResource InfoBox}">
<StackPanel>
<Button Content="I am a banana!"/>
<Button Style="{DynamicResource Strawberry}" Content="I am red!"/>
</StackPanel>
</Border>
While not exactly the same as CSS (There isn't much support for standard pseudo-selectors), this gives you a huge amount of power and flexibility. Couple this with skillful use of ItemsControls and you can do some great things.
you can set the style directly on the <Border> using an x:key and the StaticResource (or DynamicResource) property of the Border. if you would like to change the style at runtime, then you should lean towards using the DynamicResource over the StaticResource.
<Style x:Key="something" TargetType="{x:Type Border}">
</Style>
<Border style="{StaticResource something}"/>
<Style x:Key="styleKey" TargetType="{x:Type Border}">
... change some properties here
</Style>
and
<Border Style="{StaticResource styleKey}"

How can I set a border around a control during runtime in WPF?

I have an Image control on my WPF Form. How can I create a border around it during runtime?
Here's my XAML code:
<Image Margin="2.5"
Grid.Column="1" Grid.Row="0"
x:Name="Behemoth" Source="Images/Hero/Behemoth.gif" Stretch="Fill"
MouseEnter="HeroMouseEnter"
MouseLeave="HeroMouseLeave"
MouseDown="HeroMouseClick" />
Also, I want to know how to remove the border.
Maybe if I state my problem better there is an even better solution available.
I have many Images, and when a user says: "Hey, just show me the woman out of all the picture." I want a way to sort of highlight or draw the users attention to whatever images I need them to see. I was thinking about adding a border, but maybe that's too much work for something that can be solved easier.
Any help?
Although it's visually very different from a border, you could use an outter glow to signify the importance of the image. Then, you don't have to change the parent of the image.
Alternatively, you could use a custom Adorner to place a border around the image. Good info on Adorners can be found on msdn.
There's no straightforward way to do it, because the Border is a container, so you would have to remove the Image from its parent, put the Border instead, and put the Image back in the Border...
Another option would be to use templates :
<Window.Resources>
<ControlTemplate x:Key="imageWithBorder" TargetType="{x:Type Image}">
<Border BorderBrush="Red" BorderThickness="2">
<Image Source="{TemplateBinding Source}" />
</Border>
</ControlTemplate>
</Window.Resources>
...
<Image Name="image1" Source="foo.png"/>
When you want to put the border around the image, just assign the template to the image :
image1.Template = this.FindResource("imageWithBorder") as ControlTemplate;
For your stated needs, I suggest you use a ListBox with a custom ItemContainerStyle - one that always has a border but only makes it visible if the item is selected.
Here's the basic idea:
<ListBox ItemsSource="{Binding MyImageObjects}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter ElementName="border" Property="BorderBrush" Value="Blue" />
<Setter ElementName="border" Property="BorderThickness" Value="2" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

Categories

Resources