WPF BubbleSeries, iterate over the bubbles and set the style - c#

I have a BubbleSeries within a Chart. I bind data to the BubbleSeries and set a specific color to the bubbles.
What I want to do is to iterate over all the bubbles and set each bubble's color to specific color depending on the value.
My bubbles, two series:
The gray bubbles should always be gray, but the blue bubbles should have different colors depending on their SizeValue.
Any clues how to iterate over the bubbles and set their specific color? Possible?

I actually found a solution:
I didn't need to iterate over my bubbles, instead I solved the problem with a ValueConverter.
I have a ValueConverter that takes a value and return a color depending on that value.
I bind the response from my ValueConverter to my DataPointStyle:
<Charting:BubbleSeries.DataPointStyle>
<Style
TargetType="Charting:BubbleDataPoint">
<Setter
Property="Background">
<Setter.Value>
<SolidColorBrush
Color="{Binding Path=PropertyOnObjectBoundToGraph, Converter={StaticResource colorFormater}}"></SolidColorBrush>
</Setter.Value>
</Setter>

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

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.

DataGrid column headers, cant style properly

I want to change the padding and colors of a DataGrid's column headers. The padding works fine but if I change the background color the cell grippers dissappear and there is no longer mouse over or mouse pressed affects on the cells. Here's what I am doing -
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Collection}" AlternatingRowBackground="#FFF7F7F7">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Padding" Value="20,10,20,10"/>
<Setter Property="Background" Value="#FFAACCFF"/>
</Style>
</DataGrid.ColumnHeaderStyle>
...
...
...
</DataGrid>
Anybody know how to change the background color properly? I would also like to change the colors of the mouse over and mouse pressed events. I think it has something to do with triggers, anyone know?
Edit: Here is a picture of what my DataGrid header looks like, as you can see no grippers and no mouseover color change (it doesnt show in the screenshot but my mouse is on top of Property2).
Something you might consider is changing the row color during the Row PrePainting or Row PostPainting event; it should give you better control on some of the smaller things you want to do and allow you to customize it based on the values in the grid/row.
I would suggest you to define your own ControlTemplate for DataGridColumnHeader. Inside that template define your own gripper and color.
As you mentioned you can use triggers to change color inside control template. Internet is full of examples which uses triggers to change color for example take a look at this post

Set the MenuItem BackGround color (The right way)

Whenever I try to change the background color to a menu adding the following code to the app.xml
<Style TargetType="MenuItem">
<Setter Property="Background" Value="#FF9B9B9B" />
</Style>
I get this lighter shade of gray around the menu, which color isn't set by the background property:
I know there are similar questions around, but the answers I've found haven't helped me.
That sort of thing is coded into the various ControlTemplates for MenuItems. You will probably have to create your own. (You could copy the defaults and edit them to your liking though)

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.

Categories

Resources