Binding on dynamically-added elements - wpf

TPTB have decided that our app must run in a single window, popping up new windows in modal mode is not allowed.
And naturally, we have a UI design that involves popping up modal dialogs all over the place.
So I added a top-level Grid to the Window. In that Grid I defined no rows or columns, so everything draws in Row 0/Column 0.
The first element in the Grid was another Grid that contained everything that was normally displayed in the Window. The second was a full-sized Border with a gray, semi-transparent Background. The rest were Borders with wide Margins and white Backgrounds, containing the various UserControls that needed to be displayed as popups. All but the first had Visibility="Collapsed".
And then, when I needed to show a popup, I'd set Visibility="Visible" on the gray background and on the appropriate UserControl. The result was a nice shadowbox effect that worked fine.
Until somebody decided that the popups needed to be able to display popups. In a non-predictable order.
The limitation of the method I had implemented, using Visibility="Collapsed" elements in a Grid was that their order was fixed. UserControlB would always be displayed on top of UserControlA, even if it was UserControlB that asked to have UserControlA displayed. And that's not acceptable.
So my next attempt was to define the various UserControls in Window.Resources, and to add them to the Grid in code:
this.masterGrid.Children.Add(this.Resources["userControlA"] as UserControlA);
And that almost works. But the bindings are all messed up.
As an example, one of the controls is supposed to bind a Property to the CurrentItem of a collection in a member object of the Window's viewmodel. When I had the control defined as an invisible item in the Grid, it worked fine. But when I defined it as a Resource, the Property was null - it was never bound.
So I tried binding it in code, after I added it to the grid:
userControlA.SetBinding(UserControlA.myProperty, new Binding()
{ Source = this.viewModel.myCollection.CurrentItem });
And that compiles and runs just fine, but I'm not binding to the right object.
The first time I display the UserControl, I see the right object bound to it. But when I close it, and move the CurrentItem in the collection to a different object, and display the UserControl again, I still see the first object bound. If I close it again, and open it a third time, then I will see the right object bound to the control.
I've checked in code, and the CurrentItem that I'm binding to is right, every time, but it only seems to take every other time.
So I tried explicitly clearing the binding, first:
BindingOperations.ClearBinding(userControlA, UserControlA.myProperty);
userControlA.SetBinding(UserControlA.myProperty, new Binding()
{ Source = this.viewModel.myCollection.CurrentItem });
But that doesn't seem to have made any difference.
In all, it feels like I'm running down a rabbit hole, chasing deeper and deeper into complexity, to solve what should be a fairly simple problem.
Does anyone have any suggestions as to:
How to get binding to work on dynamically-added elements, or
How to get arbitrarily-ordered popups to display, as shadowboxes, without using dynamically-ordered elements?
Thanks in advance.

While it seems really odd for me that you can't create new Windows, I would definitely recommend not to complicate it too much by doing unnecesary things such as storing your views in the MainWindow's resources.
It would be better if you just added new instances of these elements into an ObservableCollection:
XAML:
<Window x:Class="WpfApplication4.Window8"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="Window8" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewModel1}">
<StackPanel Background="Green">
<TextBlock Text="This is ViewModel1!!"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel2}">
<StackPanel Background="Blue" HorizontalAlignment="Center">
<TextBlock Text="This is ViewModel2!!"/>
<TextBlock Text="{Binding Text2}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel3}">
<StackPanel Background="Red" VerticalAlignment="Center">
<TextBlock Text="This is ViewModel3!!"/>
<TextBlock Text="{Binding Text3}"/>
<TextBox Text="{Binding Text3}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<DockPanel>
<Button Width="100" Content="Add" Click="Add_Click" DockPanel.Dock="Top"/>
<Button Width="100" Content="Remove" Click="Remove_Click" DockPanel.Dock="Top"/>
<ListBox ItemsSource="{Binding ActiveWidgets}" SelectedItem="{Binding SelectedWidget}">
<ListBox.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListBox.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter ContentSource="Content"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DockPanel>
</Window>
Code Behind:
using System.Linq;
using System.Windows;
using System.Collections.ObjectModel;
using System;
namespace WpfApplication4
{
public partial class Window8 : Window
{
private WidgetsViewModel Widgets { get; set; }
public Window8()
{
InitializeComponent();
DataContext = Widgets = new WidgetsViewModel();
}
private Random rnd = new Random();
private int lastrandom;
private void Add_Click(object sender, RoutedEventArgs e)
{
var random = rnd.Next(1, 4);
while (random == lastrandom)
{
random = rnd.Next(1, 4);
}
lastrandom = random;
switch (random)
{
case 1:
Widgets.ActiveWidgets.Add(new ViewModel1() {Text = "This is a Text"});
break;
case 2:
Widgets.ActiveWidgets.Add(new ViewModel2() { Text2 = "This is another Text" });
break;
case 3:
Widgets.ActiveWidgets.Add(new ViewModel3() { Text3 = "This is yet another Text" });
break;
}
Widgets.SelectedWidget = Widgets.ActiveWidgets.LastOrDefault();
}
private void Remove_Click(object sender, RoutedEventArgs e)
{
Widgets.ActiveWidgets.Remove(Widgets.SelectedWidget);
Widgets.SelectedWidget = Widgets.ActiveWidgets.LastOrDefault();
}
}
public class WidgetsViewModel: ViewModelBase
{
public ObservableCollection<ViewModelBase> ActiveWidgets { get; set; }
private ViewModelBase _selectedWidget;
public ViewModelBase SelectedWidget
{
get { return _selectedWidget; }
set
{
_selectedWidget = value;
NotifyPropertyChange(() => SelectedWidget);
}
}
public WidgetsViewModel()
{
ActiveWidgets = new ObservableCollection<ViewModelBase>();
}
}
public class ViewModel1: ViewModelBase
{
public string Text { get; set; }
}
public class ViewModel2: ViewModelBase
{
public string Text2 { get; set; }
}
public class ViewModel3: ViewModelBase
{
public string Text3 { get; set; }
}
}
Just copy and paste my code in a File - New - WPF Application and see the results for yourself.
Since the Grid always places the last UI Element added to it topmost, you will see that Adding items to the observablecollection makes these "different widgets" always appear on top of each other, with the topmost being the last one added.
The bottom line is, when WidgetA requests to open WidgetB, just create a new WidgetBViewModel and add it to the ActiveWidgets collection. Then, when WidgetB is no longer needed, just remove it.
Then, it's just a matter of putting your UserControls inside a proper DataTemplate for each ViewModel. I strongly suggest you keep a separate ViewModel for each of your Widgets, and if you need to share data between them, just share data between the ViewModels.
Don't attempt to do things like ListBox ItemsSource="{Binding Whatever, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}" unless you have a good reason to.
This way you no longer have to deal with Panel.ZIndex stuff. Maybe you can create a couple of attached properties to deal with things like focus and whatnot, but this approach is dead simple, and by far more performant than the Visibility and the Resources approaches.

Related

WPF - How to implement DataTemplate with complex logic?

I am currently transferring my app from WinForms to WPF.
Since I'm new in WPF, I stucked at creating DataTemplates for my treeView items. The screenshot shows how my treeview looked in WinForms version, and I need to get close result in WPF.
(My WinForms treeview)
As you can see, my DataTemplate's logic should take into account these factors:
Node type / defines which icon and fields combination will be displayed for particular item (node). App has about 7-8 node types. Type stored in separate node's field.
Variable values / I need to replace with text if null, etc
Numeric variable values / e.g.: set gray color if zero, etc.
Other properties / e.g.: adding textblocks depending on boolean fields.
And so on...
All these factors result into huge amount of possible item params combinations.
Also I'm using DevComponents WPF DotNetBar AdvTree to divide item properties into columns. I presume I should create 'sub templates' for different field sets and compose from them the entire DataTemplate for each column.
I've learned about triggers, and have to say that implementing my logic with triggers will make my subtemplates huge anyway.
(Current state of my WPF treeview)
So here are my questions:
Are there any ways to dynamically compose complex templates with C# code (without creating raw XAML and loading it at runtime)?
Maybe I should use completely different way (instead of using DataTemplate)? In Winforms I just used OwnerDraw mode, so the task was MUCH easier than in WPF :(
And how to display nested properties inside template? e.g.: Item.Prop.Subprop1.Subprop2.Targetprop.
PS: English is not my first language, sorry for your eyes.
1) The answer is yes.
For exemple if you want to define a template in your window for a simple string
public MainWindow()
{
InitializeComponent();
DataTemplate template = new DataTemplate(typeof(string));
FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
borderFactory.SetValue(Border.PaddingProperty, new Thickness(1));
borderFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));
borderFactory.SetValue(Border.BorderBrushProperty, Brushes.Red);
FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock));
textFactory.SetBinding(TextBlock.TextProperty, new Binding
{
Mode = BindingMode.OneWay
});
borderFactory.AppendChild(textFactory);
template.VisualTree = borderFactory;
myControl.ContentTemplate = template;
}
And in the Window you just put something like
<ContentControl x:Name="myControl" Content="Test text" Margin="10"/>
Your content control will render the string surrounded by a red border.
But as you anc see it is really complex to define your templates in this way.
The only scenario where i could imagine this approache is for some kind of procedurally generated templates.
Another way is to generate a string for the template and then load it with XamlReader:
string xaml = "<Ellipse Name=\"EllipseAdded\" Width=\"300.5\" Height=\"200\"
Fill=\"Red\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"/>";
object ellipse = XamlReader.Load(xaml);
2) I don't really see the need to generate templates in code behind. For exemple for this kind of data structure:
public class User
{
public string Name { get; set; }
public User Friend { get; set; }
}
public class RootNode
{
public string Title { get; set; }
public User User { get; set; }
public List<Node> Nodes { get; set; }
}
public class Node
{
public string Title { get; set; }
public List<SubNode> SubNodes { get; set; }
}
public class SubNode
{
public string Title { get; set; }
}
You can define this type of template:
<Window
...
Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:RootNode}" ItemsSource="{Binding Nodes}">
<StackPanel x:Name="spContainer" Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding User.Friend.Friend.Name}"/>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding User}" Value="{x:Null}">
<Setter TargetName="spContainer" Property="Background" Value="Yellow"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding SubNodes}">
<TextBlock Text="{Binding Title}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:SubNode}" ItemsSource="{Binding Nodes}">
<TextBlock Text="{Binding Title}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding RootNodes}"/>
</Grid>
</Window>
As you can see you can define a template by data type, you can also use triggers to modify the behavior in specific cases, you could also use som binding converters...
3) You can bind to nested properties just like to normal ones :
<TextBlock Text="{Binding User.Friend.Friend.Name}"/>
However in some cases more than two level bindings could fail (fail to resolve or fail to update when property changes, ...)

selected item from listbox XAML

I am trying to get the selected item from the ListBox using listbox_SelectionChanged() method, but it does not seem to work. Could you tell me what is the best way to get the selected item out of listbox. the code I tried is bellow.
your help much appreciated.
XAML
<ListBox
x:Name="lbSkills"
Grid.Row="1"
Margin="10,0,10,10" SelectionChanged="LbSkills_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="Beige">
<Grid Width="auto" HorizontalAlignment="Stretch">
<TextBlock VerticalAlignment="Center" FontSize="26" Grid.Column="0" Foreground="Black" Text="{Binding SkillDescription}"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
XAML.cs - I have also tried commented code, but unable to get the selected item
private async void LbSkills_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//var addedItems = e.AddedItems;
//string selectedSkillString = "None";
//if (addedItems.Count > 0)
//{
// var selectedSkill = addedItems[0];
// selectedSkillString = selectedSkill.ToString();
//}
//lbSkills.SelectedItem.ToString();
MessageDialog msgBox = new MessageDialog(e.AddedItems.ToString());
await msgBox.ShowAsync();
}
First of all check what is the DataConntext or ItemsSource of you ListBox (it have to be an ObservableCollection to avoid the memory leaks).
Check if there is a Binding errors in the Output window.
Check if there is a correcct property to bind to.
Try the solution the next solution:
As I can understand you, the problem is that the added items of event argument doesn't contains the current selected item. But there is no any problem with your code. It returns the actual model (Skill) when I used it. But if you apply ToString() metod on it, you won't get the real model, the result will be just the full name of a class (<Full.Assembly.Path>.<Class_Name>). If you want to get the model instance you have to cast or safely cast the e.AddedItems content or you have to override the ToString() method in your model class. From another hand if you want to get the ListBoxItem itself for some reason try to use the next code:
var listBox = sender as ListBox;
var selected = e.AddedItems.Cast<object>().FirstOrDefault();
var container = listBox.ItemContainerGenerator.ContainerFromItem(selected);
regards

WPF databinding with a user control

I have a wpf user control, which exposes a single custom dependency property. Inside the user control, a textblock binds to the value of the dp. This databinding works in all scenarios except when the data source is an object.
The minimal code necessary to reproduce this is:
this is the main part of the user control
<StackPanel Orientation="Horizontal">
<TextBlock Text="**SimpleUC** UCValue: "/>
<TextBlock Text="{Binding UCValue}"/>
</StackPanel>
and the user control code behind:
public SimpleUC()
{
InitializeComponent();
this.DataContext = this;
}
public string UCValue
{
get { return (string)GetValue(UCValueProperty); }
set { SetValue(UCValueProperty, value); }
}
public static readonly DependencyProperty UCValueProperty =
DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));
this is the test window. I imported my project xml namespace as "custom"
<Window.Resources>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="20"/>
</Style>
</Window.Resources>
<StackPanel>
<StackPanel>
<TextBlock Text="This fails to bind:"/>
<custom:SimpleUC UCValue="{Binding SomeData}"/>
</StackPanel>
<StackPanel>
<TextBlock>The same binding on a regular control like Label</TextBlock>
<Label Content="{Binding SomeData}"/>
</StackPanel>
<Slider x:Name="sld" />
<StackPanel>
<TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
<custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
</StackPanel>
</StackPanel>
and the test window code behind is:
public TestWindow()
{
InitializeComponent();
this.DataContext = this;
}
//property to bind to
public string SomeData { get { return "Hello S.O."; } }
When I turn on the diagnostic tracing on the TestWindow, it spits out the error "BindingExpression path error:
'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
The binding expression is the same as the one I used in the neighboring label and it worked fine. This behavior seems really bizarre to me. Can anyone shed some light?
You set DataContext of your SimpleUC to itself here
public SimpleUC()
{
InitializeComponent();
this.DataContext = this; // wrong way!
}
so when you use binding here
<custom:SimpleUC UCValue="{Binding SomeData}"/>
it searches property SomeData in control's data context which is set to this object because code in SimpleUC constructor overrides value of DataContext and it is not set to TestWindow object anymore as you expected. That's why your solution works - it doesn't affect DataContext which is inherited from window. Also you can keep this.DataContext = this; but set element where to search property explicitly like this (skipped irrelevant)
<Window ... Name="wnd1">
<custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
...
But my oppinion is that your variant from the answer looks more convenient to me, setting data context to this is not very good practice.
Hope it helps.
If you must use a UserControl, your
<TextBlock
Text="{Binding RelativeSource={RelativeSource Self},
Path=Parent.Parent.UCValue}"
/>
is an ok way to do it and
<TextBlock
Text="{Binding UCValue,
RelativeSource={RelativeSource FindAncestor,custom:SimpleUC,1}}"
/>
is better because you don't rely on the control hierarchy and possible instantiation order issues.
However I would recommend for this kind of situation that you use "custom controls" instead of "user controls". They take a little bit of getting used to, but they are much more powerful because their XAML is the template itself which means you can use TemplateBinding and {RelativeSource TemplatedParent}.
In any case, DataContext = this; is definitely to be avoided.

WPF, MVVM, and Menu Foreground Color

I'm new to both WPF and MVVM. I have searched for a good way to dynamically create menus in the MVVM parttern and I am not finding anything to my liking, so I rolled my own solution. It works, but for some reason the Foreground (text) color of the menus are sometimes (just sometimes) not correct.
I added a link for the image below.
http://img220.imageshack.us/img220/1912/badmenu.jpg (Dead Link)
My lowest submenu displays correctly with a white foreground, but its parent menus forground turned to black and is almost impossible to read. If I had hard coded the menus then the parent's forground color would be white. If I move my mouse over the parent its text will switch back to white and the submenu will become black.
Further, once I move my mouse away from the parent, all of its boolean properties IsHighlighted, IsSubmenuOpen, etc... become false, which surprising to me because I would think they should stay true. The end result is I haven't been able to solve this with a style trigger.
Here is my XAML .
<Window.Resources>
<DataTemplate DataType="{x:Type src:ParentMenu}" >
<Menu >
<MenuItem Header="{Binding MenuName}" ItemsSource="{Binding ChildMenuItems}" />
</Menu>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type src:ChildMenu}"
ItemsSource="{Binding ChildMenuItems}" >
<MenuItem Header="{Binding MenuName}" Command="{Binding Path=Command}" />
</HierarchicalDataTemplate>
' StackOverflow is masking my end tag for Window.Resources
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />
<Grid>
<!-- Add additional content here -->
</Grid>
</DockPanel>
Both ParentMenu and ChildMenu inherit from a common class that actually holds all the menus and exposes the sub-menus through the ChildMenuItems collection. ChildMenuItems is a list of ChildMenu objects. My ViewModels expose a list of ParentMenu objects.
There are probably better ways to accomplish what I want here. Here is an example:
img132.imageshack.us/img132/4160/bettermenu.jpg (Dead Link)
Any suggestions on what I'm doing wrong and/or how to fix the display problem?
The problem is that your VMs automatically get wrapped in MenuItems, so you essentially have MenuItems nested as the Header of MenuItems.
You can get around this by defining a Style (and pointing to it via ItemContainerStyle) that DataBinds to your VMs (Name to Header, DelegateCommands to Command, etc.) using MenuItem as the DataType.
An example of a way you can do this is below. Note that I've dropped the HierarchicalDataTemplate in favor of an ItemContainerStyle. I also took the liberty of defining a DataTemplate for your MainViewModel as it wasn't very clear how that was data bound.
<Window.Resources>
<DataTemplate DataType="{x:Type src:MainViewModel}">
<ItemsControl ItemsSource="{Binding Menus}"></ItemsControl>
</DataTemplate>
<DataTemplate DataType="{x:Type src:ParentMenu}" >
<Menu>
<MenuItem Header="{Binding Name}"
ItemsSource="{Binding ChildMenuItems}" ItemContainerStyle="{DynamicResource ChildMenuItemStyle}" />
</Menu>
</DataTemplate>
<Style x:Key="ChildMenuItemStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}"></Setter>
<Setter Property="ItemsSource" Value="{Binding ChildMenuItems}"></Setter>
</Style>
</Window.Resources>
I've also cut some of the Command binding out for simplicity, but you can add it back in as necessary.
As requested, here are my ViewModels.
ViewModelBase is the standard one created by studio. MainVieModel has got just enough to in it to create the test menus I was using to experiment with.
Basically I am working towards creating a Parent/Child menu classes I can use with a series of apps we sell to a broad collection of clients. I hope to make it where each customer can have a customizable collection of menus based upon their needs and which moudles they've purchased licenses for.
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MainViewModel : ViewModelBase
{
public MainViewModel() { MakeMenus(); }
private void MakeMenus()
{
// Makes some dummy menus to test with.
Menus = new ObservableCollection<MyMenuItem>();
ParentMenu parent;
ChildMenu child;
parent = new ParentMenu("First Level");
Menus.Add(parent);
child = new ChildMenu(parent, "second level");
parent.ChildMenuItems.Add(child);
ChildMenu child2 = new ChildMenu(child, "third level");
child2.MenuCommand = new DelegateCommand(CommandTest,
CommandCanExecute_First);
child.ChildMenuItems.Add(child2);
child = new ChildMenu(parent, "second level 2");
parent.ChildMenuItems.Add(child);
child2 = new ChildMenu(child, "third level 2");
child2.MenuCommand = new DelegateCommand(CommandTest,
CommandCanExecute_Second);
child.ChildMenuItems.Add(child2);
parent = new ParentMenu("Another First");
parent.ChildMenuItems.Add(new ChildMenu(parent, "Another Second"));
Menus.Add(parent);
OnPropertyChanged("Menus");
}
private bool ExecuteToggle { get; set; }
private void CommandTest() { ExecuteToggle = !ExecuteToggle; }
public ObservableCollection<MyMenuItem> Menus { get; private set;}
public bool CommandCanExecute_First() { return ExecuteToggle; }
public bool CommandCanExecute_Second() { return !ExecuteToggle; }
}

How to rotate Items in a WPF Listbox style?

I want to make a WPF ListBox photo album for one my college projects.
I need to design a DataTemplate/ListBox style so it will look like a stack jumbled of photos, i.e., the top one being the item in focus/selected (see diagram below).
Image here
With reference to the drawing,
item 1) is not shown
item 2) is at the back of stack
item 3) in the middle of 2 and 4
item 4) is in focus
item 5) is not shown
I am having the most trouble getting the items to rotate and overlap and the most difficult task is getting the item in focus to be shown on top.
I'm using Visual Basic because I haven't yet mastered C# so it would be useful if examples could be in VB or use mainly WPF.
To get the items to rotate, you should look at using Transforms. The one that is most relevant in this case is the Rotate Transform, also to give it that random scattered apperance, we can use an ObjectDataProvider and generate our angles somewhere else.
I don't know VB, but the only C# involved in this is pretty simple, and should be easily transferable.
Lets just use something simple like Colors, which can easily be switched over to image resource paths. Here we've got an ObservableCollection of our Colors, and also a separate class that we will use to generate angles, all it's going to do is return a number between 0 and 360, which we will use to rotate each item.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Colors = new ObservableCollection<string>();
Colors.Add("Red");
Colors.Add("Blue");
Colors.Add("Green");
Colors.Add("Yellow");
this.DataContext = this;
}
public ObservableCollection<string> Colors
{
get;
set;
}
}
public class AngleService
{
private static Random rand = new Random();
public int GetAngle()
{
return rand.Next(0, 90);
}
}
In the XAML, we can now create a resource that can be used to generate the angles.
<Window.Resources>
<local:AngleService x:Key="Local_AngleService" />
<ObjectDataProvider x:Key="Local_AngleProvider"
x:Shared="False"
ObjectInstance="{StaticResource Local_AngleService}"
MethodName="GetAngle" />
</Window.Resources>
Now, we just need to create something to display our items. We can put them in a ListBox and add a data template to set the background for each color item, as well as apply the RotateTransform.
<ListBox ItemsSource="{Binding Colors}"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center">
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="uiItemBorder"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="3"
Background="{Binding}"
Width="50"
Height="50">
<TextBlock Text="{Binding}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<Border.RenderTransform>
<RotateTransform Angle="{Binding Source={StaticResource Local_AngleProvider}}" />
</Border.RenderTransform>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The UI still needs a bit of work from there, but that should help out with the rotation of the items.

Resources