Fonts in designer are different size to those at runtime - c#

I have a Silverlight OOB application. Some of the TextBlocks (but not all) have started to behave strangely. When viewed in the Designer, they're the size I want them to be. When I run the app, they appear roughly 1pt bigger.
I've checked it with Silverlight Spy, and the font size/weight are the same as at design time. If I make the fonts too small in design mode, they come out the right size at runtime. If I use Silverlight Spy to make them 1pt too small at runtime, they look the right size. Silverlight Spy shows that the TextBlocks aren't affected by a style.
What could be causing this? I'm using VS 2010 and Silverlight 5.

In cases where I have observed differences in font rendering in WPF or Silverlight, it was almost always due to the FontFamily being different rather than the FontSize. If you can, verify with Silverlight Spy that the font families are in fact the same.
Interestingly, there can be differences even if the effective font family is the same. In one of our applications, we are using a composite FontFamily definition that uses Segoe UI for most western glyph ranges, but a serifed font for the Greek glyph ranges to better differentiate those characters (this is a finance application). I noticed that the line height was slightly different in the editor than in the runtime application. It seems the editor doesn't always apply composite fonts correctly (or didn't, prior to some of the VS2012 updates).

Check if there are any Transforms present.

I had this problem with Labels, Buttons and Checkboxes. After a look using WPF inspector, it had come to my attention that the text in each of the above contains a TextBlock to display the actual text, and I had set my default FontSize for a Text Block to 13 which was then overriding the value I specified for (e.g) the Label.
This sorted me out
<ControlTemplate x:Key="LabelTemplate" TargeType="Label">
<TextBlock Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}" />
</ControlTemplate>
<Style TargetType="{x:Type Label}">
<Setter ... etc. etc. other styling I had already in here />
<Setter Property="Template" Value="{StaticResource LabelTemplate}" />
</Style>

Related

Display bordered tiles in ListBox with large number of items in WPF

I'm trying to build a GUI similar to the one on the first screenshot:
Basically it's a view of tiles, displayed in a bordered grid that dynamically changes number of columns as the window is resized. The items are selectable. Those may look like pictures, but they are just Unicode characters.
I've made a List of custom objects, and bound the list to a ListBox control successfully. Naturally, this gave me a vertically stacked list of characters.
So I googled some, and found out I could set a custom ItemsPanelTemplate for the list box:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="0"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
The result was the following:
In order to set the border and size of the tiles, I've also added an ItemTemplate:
<ListBox Margin="0,0,0,0" Padding="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="tw"
SelectionChanged="tw_SelectionChanged"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="0,0,0,0"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label
Padding="0,0,0,0"
Margin="0,0,0,0"
Width="50"
Height="50"
FontSize="20"
Background="White"
HorizontalAlignment="Left"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
BorderThickness="1"
BorderBrush="Black"
Content="{Binding Path=LiteralString}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The result was the following:
This is as far as I got.
The first problem is, as you can see, there are spaces between the tiles that I can't get rid of. You'll notice in the markup I've tried manually setting Margin and Padding to 0 wherever possible. The spaces are still there.
The second problem is, you can't really see which item is selected. The 3rd character from the bottom and 2nd from the right is selected, but the blue color is covered by the label. You can only just see it in the space to the left of the character. I have no idea how to fix this.
Another potential problem is performance. The view will eventually have filters, but when all the filters are off, there are some 6500 items to display. When I had just a basic ListBox, the application was taking up some 28MB of RAM while it was running. When I added the ItemsPanelTemplate with the WrapPanel, memory usage jumped to about 136MB. When I added an ItemTemplate with Labels, memory usage jumped to 183MB, and what's worse, the window now takes much longer to load.
I've tried replacing Labels with TextBlocks, since I've read they're much more lightweight. The thing got faster, and memory usage dropped back to around 130MB, but TextBlocks are no good. I can't center text in them, or give them borders. And as you can see in the screenshot, the selected item just gets messed up:
Granted, I have a slow computer, and 183MB is not life-ending, but still, it's a bit inefficient. I intend to put a lot more functionality in this application, and if this one thing takes up so much RAM, the resulting application will likely be an unusable resource vampire. Also, I believe the application I'm mimicking is also written in .NET, (although I'm not sure if it's WPF) and that one only uses 17.5MB of RAM while displaying the view.
Is there another way to do this, one that's both more efficient and more easily customizable?
Thank you.
EDIT:
I have found a slightly better way. I removed the ItemTemplate altogether, and instead I'm using ItemContainerStyle:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Setters>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Width" Value="50"/>
<Setter Property="Height" Value="50"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="SteelBlue" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
This produces much better results. There are no visible spaces between the tiles, and I can customize the look of both selected and deselected tiles.
The only thing I don't know how to do is have a border line with the thickness of 1 pixel. I get two lines with thickness of 1 touching, resulting in a thickness of 2. I've tried setting margins and padding to 0 and -1. No luck. Curiously, setting BorderBrush to Black and BorderThickness to 0.5 doesn't produce a combined black line with thickness of 1, but a grey line with thickness of 2.
Memory usage dropped somewhat to about 150MB compared to when I was using labels, but load times are still atrocious, so I'm still looking for a better solution.
EDIT 2:
I played with the margins for a while, and I finally nailed it. I got the correct border thickness by setting the margin of the ListBoxItem to -0.5, squishing the tiles ever so slightly together. I would like to keep the question open, so that hopefully somebody will present a more efficient solution. The UI is responsive once it's running, but the load time is terrible. During the use of my application the ListBox will be repeatedly re-filled, as filters are adjusted and queries are made. I would like that to happen quickly. Also, memory usage is unnecessarily high in my opinion.
As i do not have enough rep to post a comment, will try to answer, or at least point to correct direction.
1) The reason you get Thickness of 2 is that adjacent borders join their respective thicknesses. And -0.5 Margin you use makes them intersect making resultant thickness of 1. Instead you can try to set border thickness of Right and Bottom side, like:
<Setter Property="BorderThickness" Value="0,0,1,1"/>
Which means LeftSide=0, Top=0, RightSide=1, Bottom=1 thick. So leftmost items won't have left border, and topmost items won't have top border. And as a result adjacent borders will not marge, doubling their thickness.
2) And for excessive memory usage and overall slow performance. When you use WrapPanel for ItemsPanel you are discarding UI Virtualization. Because usually non UI computation doesn't take much time first consideration is UI performance. Try to load your data and make computations without UI, I think difference will be obvious.
I suggest you use some sort of VirtualizingWrapPanel for ListBox ItemsPanel. Personally I use this one with corrections suggested by more experienced coders:
Original implementation
First correction
Second correction

WPF Custom Transparent Button

I would like create a button with text and image inside in, but this button should be transparent without loose behavior as cursors hand on mouse over and so on..
Also, it doesn't change its background color on mouse over. It's Always should appear transparent showing only my text and my image.
Is it possibile?
I think a very simple ControlTemplate will produce the desired output :
<ControlTemplate x:Key="TransparentButton" TargetType="Button">
<ContentPresenter Cursor={TemplateBinding Cursor}/>
</ControlTemplate>
Then simply apply if to the Templateproperty of your button.
Just add a {TemplateBinding Property} for the any properties you want to inherit. You should have a look at the default ControlTemplates on MSDN for your specific target (it may vary if targeting WP8, Silverlight or desktop)

Border around extension of 'Run' element

I'm creating a WPF application which shows a list of styled messages. My goal is to have the contents of multiple styled messages selectable, similar to how you can in Skype:
Currently, I have a ListBox which contains an extension of ListBoxItem that is styled to my needs:
However, this method does not satisfy my goal of being able to select the text of multiple messages at the same time. It is only possible to select the text inside one message.
I also tried to put my custom elements inside a RichTextBox control within BlockUIContainers (which is what I suspect I will end up having to use), but the text inside each element cannot be selected, only the entire element:
Next, I attempted to extend the "Run" element, but I cannot figure out how to put a border around it to style an individual message.
<Run.Style>
<Style TargetType="{x:Type Run}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Run}">
<Border Background="{TemplateBinding Background}" x:Name="Bd" CornerRadius="2">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Run.Style>
With this XAML, I tried to surround the content of the Run using a template, a border element, and a content presenter. However, the Run control does not appear to support templates.
If anybody could point me in the right direction, that would be greatly appreciated.
I don't know if this will help you but is just another idea...
Use one text control with transparent background so you can select all the text at once. Then you have to draw rectangles behind the text blocks. Like an optical ilussion.
The challenge here is calculating the exactly size of the text rectangle box and the text allignment. My idea is having a predefined sizes and positions design (left text box, right text box, date, etc) so the size and positioning calculations are easier.
Another idea is play with the mouse and/or selection events. During the user text selection replace it programatically with your own selection. The user will think that is he who is selecting the text but is the application who is doing it. Another illusion...
I hope you could resolve it.

What is ScaleTransform good for?

why I should use ScaleX="2" for example instead of double the width of my control ??
<Button Width = "100" Content="Button1"/>
<Button Width = "50" Content="Button2">
<Button.RenderTransform>
<ScaleTransform ScaleX="2" />
</Button.RenderTransform>
</Button>
both buttons look exactly the same so again, what scale is good for
Your concept of "exactly the same" seems to be different from mine.
The sizes you specify with Width and Height affect how much space the control takes up in the layout, this means that the control may take more or less space but the font size will stay the same for example. The RenderTransform is a manipulation on top of this which no longer concerns the layout and hence may distort the control.
A render transform does not regenerate layout size or render size
information. Render transforms are typically intended for animating or
applying a temporary effect to an element. For example, the element
might zoom when focused or moused over, or might jitter on load to
draw the eye to that part of the user interface (UI).
See also the LayoutTransform property, which does affect layout but still distorts the control.
What if it was more complicated than a Button with a Width? What if you had a complex Path/Geometry, or maybe even a group of controls? You wouldn't want to go and manually change everything. What if you had a custom control, where you wanted to give one instance the size 100x100, and another instance 150x150? What if you were implementing zoom functionality (think google maps)?
In short, for your specific example, it doesn't provide much use. But there are many other cases where it does.
It's useful when you don't have the ability to scale some parts of a control. Consider the DatePicker control. The default implementation has a drop-down calendar that was too small for my users' liking, so I introduced this snippet of XAML into my App.xaml file:
<Style TargetType="w:DatePicker">
<Setter Property="CalendarStyle">
<Setter.Value>
<Style TargetType="w:Calendar">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" />
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
Now the calendar is 1.5 times as big, and my users are happy. There is no "CalendarWidth" or "CalendarHeight" property that I can set directly, so the ScaleTransform saved the day.

WPF Control Templating: Keeping Windows look and feel

I'm working on a control template for an inherited TextBox class. I'd like to use this template to add additional controls with the ScrollViewer. I can achieve that goal just fine, what I can't do recreate the border in such away that it matches the Windows look and feel.
I have Windows Classic as my theme on XP. Textboxes are typically shown with the standard inset border style. With the XP Fischer Price theme, borders of textbox are a flat style and light blue.
Is there any way of specifying something like this in the template? Ideally it would use the theme default (grey inset for Classic, flat and light blue for fischer price theme).
You will have to provide a separate ControlTemplate for each known theme. There is no generic way to create a theme-agnostic ControlTemplate. Infact WPF itself maintains separate ControlTemplates for each official theme (excpet the Zune theme, where WPF falls back to battleship gray).
I'm not sure if this will work as I am not sure what your setup is. I also don't know if you are concerned about changing themes on the fly. You can try to set the style for your text box class to have
BasedOn="{DynamicResource {x:Type TextBox}}"

Categories

Resources