Binding to the actual of a UserControl in Silverlight? - silverlight

Seen some questions on SO but none answers my question.
What I want to accomplish:
I have a custom control (lets call it A) which moves around the canvas using a storyboard. And I want to bind another custom control's canvas (lets call it B) position onto the first control.
Using the TransformToVisual(Application.Current.RootVisual) I can get the actual position of control A, but I can't figure out how to get a binding to B's Canvas.Left and Canvas.Top on this.
Has anyone figured out how to accomplish this task? Or get me pointed into the right direction?

I presume you move the position of control A by updating its Canvas.Left and Canvas.Right properties? If this is the case, you do not need to use TransformToVisual, you can just bind their Canvas Top & Left properties together:
<Canvas >
<TextBlock x:Name="ControlB"
Text="Some Text"
FontSize="15"
Canvas.Left="{Binding ElementName=ControlA, Path=(Canvas.Left)}"
Canvas.Top="{Binding ElementName=ControlA, Path=(Canvas.Top)}"/>
<TextBlock x:Name="ControlA"
Text="Some Text"
FontSize="13"
Canvas.Left="100"
Canvas.Top="100"/>
</Canvas>
Regards,
Colin E.

Related

Control the width of child in Stackpanel

I'm trying to implement a certain layout.
I have two elements that I want to stack vertically (I need them to follow each other closely). I am currently trying to achieve it using a Stackpanel.
The problem is that I want the first element to have a limited width and the other to use all the width available in the StackPanel. Ideally, I would like that the first element have a width equals to the width of four columns from the grid that contains the StackPanel, here is my code.
<Grid>
<!-- Colums and Rows definition go here -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="8">
//The first element
<Viewbox Name="viewbox_choix" Margin="160,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="4">
//The second element
<StackPanel Grid.Column="0" Grid.ColumnSpan="5">
<Border></Border>
etc...
</StackPanel>
</StackPanel>
</Grid>
The grid attributes are referring to the parent grid of the stackpanel. But the Grid.Column and Grid.ColumnSpans seem to have no effect when I try to use them inside the StackPanel.
The problem of that code is that the first element also uses all the width of the StackPanel but that isn't what I want...
Can anybody help me ? I precise that I'm still learning WPF and I don't really know how bindings work...
In WPF, a StackPanel does not work like a Grid. There is no maximum width... it will happily let content disappear out of its right side. If you want automatic resizing, just replace the StackPanels with `Grid
UPDATE >>>
In the Grid class, there is an attached property called IsSharedSizeScope. Add this to the parent Grid and set it to true. Then in your RowDefinitions, you can add SharedSizeGroup properties to the columns that you require.
These examples may help you:
Grid's SharedSizeGroup and * sizing (SO post)
Grid.IsSharedSizeScope Attached Property (MSDN)
You may need to experiment a bit, but you should be able to get the desired effect using these properties.

WPF show small number beside all Controls

I have many FrameworkElements (TextBlock, CheckBox, ListBox..) and I would like to make something allowing me to show a small number besides every one control.
Some text ³
I came with the idea to write a MarkupExtension, where I could write that number like this:
..
<TextBlock Text="Some Text" SomeExtension="3" />
..
and then to add it somehow to the template of the Control.
But I'm sure, you guys have better solution for this problem ;)
One way to go with it would be create a Attached Property. Upon setting it on a control, a custom Adorner would be added for that control showing specified number.
Use the tag property to provide the number you want and inside the custom template databind to the property
<TextBlock Text="Some Text" Tag="3" />
and inside the controltemplate
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>

How can I set the MinHeight of a StackPanel to be the combined height of its contents?

I have a StackPanel with several CheckBox controls inside it. How do I prevent the StackPanel from shrinking and obscuring the CheckBox controls when the window is resized?
<StackPanel Margin="12,89,12,62" Name="stackPanel1">
<CheckBox Name="chkOption1" Width="157" IsChecked="True" Margin="6">Do this thing</CheckBox>
<CheckBox Name="chkOption2" Width="157" IsChecked="True" Margin="6">Do another thing</CheckBox>
<CheckBox Name="chkOption2" Width="157" Margin="6">Do a third thing</CheckBox>
<Button Height="23" Name="btnRunOperations" Click="btnRunOperations_Click" Margin="3">Do Selected Things</Button>
</StackPanel>
EDIT: Does WPF have a different container control that has this behavior "out of the box"? This seems like a really common scenario.
Well, I guess you could set the MinimumHeight of the stackpanel to an appropriate value, either hardcoded, either calculated as the sum of the heights of all elements within.
you could use a binding and a custom converter where the converter calculates the value for you.
<StackPanel Height="{Binding Converter=MyConverter}"/>
You should wrap your StackPanel in a ScrollViewer. By default it will request to be as tall as needed to display all it's children.

If you were going to build an org chart builder in Silverlight, what base class would you use for creating the boxes of the chart?

For this question, let us assume that we will want to show the face of the employee, title, department, and whether they like Piña coladas/getting caught in the rain.
Perhaps it might look something like the following:
http://www.edrawsoft.com/images/examples/Photo-Org-Chart-Full.png
Would you use a...
System.Windows.Control.UserControl?
FrameworkElement?
UIElement?
Canvas
Why? As always, thank you for your advise! I greatly appreciate it!
If I had to create a org chart control with advanced layout I would probably derive from Control, and create a "real" templated control in a similar manner as e.g. the TreeView control. This is probably the most advanced route to create a new control, but also the most powerful.
You may also be able to modify the control template of a TreeView, and make it grow downwards from the center instead of left and down from the upper left corner, but it will probably be difficult or impossible to customize the layout of the various levels as the TreeViewItem doesn't carry any extra information to describe the layout of a particular node.
In fact I did recently some experiments modifying the TreeView control template, but I stumbled upon something I didn't understand. Luckily I figured out what I did wrong, and you can see how it is possible to change the orientation of TreeView child items from vertical to horizontal in my question here on Stack Overflow.
I've seen a website that uses TreeViewItem and ControlTemplates, but I can't find it at the moment, I think it was on CodeProject.
Another idea I was playing with recently is use 2 usercontrols, itemcontrols and stackpanels.
Here's an example of a an OrgBar rectangle with text under it and it renders it's children in OrgGroup control by setting the ItemSource to it's children collection recursively. You can put the root orgbar on a canvas and play around with paths for the arrows. I tried to point out the basics but if you need more I can fill in the blanks.
Public Class OrgBarDataNode
Public Property BarColor as New SolidColorBrush(Colors.Red)
Public Property BarName As String
Public Property Children as New ObservableCollection(Of OrgBarDataNode)
End Class
Class MainPage
...
Public Sub Loaded
Dim Root as New OrgBarDataNode With {.BarName = "Root"}
Dim Child1 as New OrgBarDataNode With {.Barname = "Child1"}
Root.Children.Add(Child1)
LayoutRoot.Children.Add(Root)
End Sub
...
End Class
<UserControl x:Class="OrgBar">
<Grid>
<StackPanel ToolTipService.ToolTip="{Binding BarName}" Cursor="Hand">
<Rectangle Fill="{Binding BarColor}" Style="{StaticResource RecStyle}"/>
<TextBlock Text="{Binding BarName}" HorizontalAlignment="Center"
Margin="0,10,0,0" />
<local:OrgGroup Margin="0,20" HorizontalAlignment="Center"
DataContext="{Binding Children}" />
</StackPanel>
</Grid>
</UserControl>
<UserControl x:Class="OrgGroup">
<Grid>
<!-- this {Binding} to nothing means bind to DataContext}-->
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:OrgBar Style="{StaticResource OrgBarStyle}"
DataContext="{Binding}" />
<!-- this {Binding} refers to the the child node this time} -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
That's essentially a tree structure, so like Paully suggested, I would start with a TreeView (Silverlight Toolkit) and customize the control template and treeview itself.

Display images in TextBlock (WPF)

I'm working on a simple chat application. Currently the messages are binded to a custom-styled listbox like this (simplified XAML):
<ListBox ItemsSource="{Binding MessageCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now I would like to be able to put images (like graphical smileys) into the displayed message text. Is there any way to achieve this using TextBlock (or any other standart component) or do I need to use some special control for this?
Thanks in advance
Just use the InlineUIContainer.
<TextBlock TextWrapping="Wrap">
<Run>Some text.</Run>
<InlineUIContainer>
<Image Source="http://sstatic.net/stackoverflow/img/apple-touch-icon.png" Height="20"></Image>
</InlineUIContainer>
<Run>Some more text.</Run>
</TextBlock>
The Content of a TextBlock is always just a series of Inlines, so you should use the InlineUIContainer. You can insert this container as one of the Inlines in your TextBlock wherever you want an Image to appear, alternating with text Runs. You could parse a message and at the same time keep adding the tokens (either text or images) that you find to the Inlines collection of the TextBlock.
If you want the Images actually inside the text (like an emoticon), then you are going to have to do some work. This sounds like one of the few times I would actually want a User Control, the point of which would be one that scans the Text looking for emoticon values and building a Data Template on the fly.
Remember that anything you can do in XAML you can do in code, so the code I'm thinking of would follow this general idea:
Scan text for emoticon values and
create a list of values for data
elements.
Create a DockPanel.
Foreach element in the List, add
either a TextBlock or an Image
(based on value).
Set this.Content to the DockPanel.
I think something like this is actually what you are looking for, but if you want just an Image, then the ValueConverter suggestion would work.
You could use a value converter to convert the text to another type which has a list of segments which are composed of either text or the smiley face (in the order in which they appear).
Then, you can use a data template to bind to that new type and display the text and smiley faces appropriately.
I also encountered this problem recently and I overcome this by
Creating an ListBox ItemTemplate containing an ItemsControl that has a WrapPanel in the ItemsPanelTemplate and then binding my string to the ItemsSource of the ItemsControl with a IValueConverter that houses all the logic.
Split out your words and query/search your emoticons strings, hyperlinks etc and create your TextBlock, Image, Hyperlink, Button elements and set your values and event handles.
In the function create a List<UIElement> and populate the List with the controls you have generated and return the List as the object in the Convert function of the IValueConverter.
Because you have the WrapPanel in there you get your wrapping done.
Use the Image element instead of the TextBlock and use a Converter to map the text value to the smile image.
<ListBox ItemsSource="{Binding MessageCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Text, Converter={StaticResource MyImageConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>

Resources