I'll post how far I got (see Update/Edit 2014-06-29 below) with this other Q/A as a edit below to this original question:
...or...
"Looking for a way to bind/tie ObservableCollections to positions on the Canvas, so code-behind can tell the ObservableCollections which cards to display where."
Experts,
That's a lot for a subject line. I'll start with the same question asked at first the highest level, then break it down i levels to explain the project idea/need:
VB/S2012, but I can convert from C#
Top Level
-Place playing cards (I have the images) on a card table (it's a canvas inside a Viewbox).
Next Level of Detail
-I imagine each possible card position is known (solitaire) in advance. An ObservableCollection seems perfect to store the cards themselves, and to have the logic act upon. -With just 52 cards, I could also enter each into a ResourceDictionary, or just into the MainWindow XAML file. Or, just as easily do it in code-behind.
A Little More Detail
-The code-behind will determine which card (face up or down) will be in which position, and there won't be any user interaction with the cards. -I have images for cards in both PNG and SVG, but the PNG files look fine at full screen, so hopefully I can avoid complex converters with SVG. -I imagine assigning the positions of all possible card positions, and somehow binding those positions in a way that my ObservableCollections can use directly (position 0 is draw pile, etc.)
Progress So Far
[note: Since I can't get a working combination, I can't say whether Image or filling a Rectangle, or even another approach is best. This is why I am asking. So do not assume I am married to either of these approaches. I just want to get to the business lofic and have this part done!]
-I can draws the Viewbox/Canvas, and with a rectangle/image object, it resizes perfectly with the main window:
<Viewbox>
<Grid>
<Canvas x:Name="TheCanvas" HorizontalAlignment="Left" Height="774" Margin="10,29,0,0" VerticalAlignment="Top" Width="969">
<Image x:Name="Foundation1" Height="679" Canvas.Left="10" Width="726" Source="images/10_of_clubs.png" />
[...]
-I've added a ResourceDictionary like so:
Application.XAML
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="CardTable.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="PlayingCardsResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
PlayingCardsResourceDictionary.xaml (in root dir of project):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingBrush x:Key="CardImages" >
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<ImageDrawing x:Name="H2" ImageSource="images/2_of_hearts.png" />
<ImageDrawing x:Name="H3" ImageSource="images/3_of_hearts.png" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</ResourceDictionary>
-I was hoping to use assignments (like "H2", "H3") in place of files & paths with this approach, but I cannot get it to show anything. -With this hard coded:
<Image x:Name="Foundation1" Height="679" Canvas.Left="10" Width="726" Source="images/10_of_clubs.png" />
...I tried to adjust the Foundation1.Source property in code, but even though this would seem to be able to work (based on above):
Foundation1.Source = "images/jack_of_diamonds.png"
...it doesn't (string worked in XAML, but not in code-behind):
Value of type 'String' cannot be converted to 'System.Windows.Media.ImageSource'.
-The images/ directory above is off the project's root folder, and Intellisense will complain if I call a file with "ImageSource=" that doesn't exist-so I know that part is right.
Example:
I can assign CardImages as a StaticResource for Card1, but CardImages has more than one image in it:
-And no attempts from code-behind can convince an image to be produced.
Needed/Summary
A way to bind/tie ObservableCollections to positions on the Canvas, so code-behind can tell the ObservableCollections which cards to display where. (so good I'll use it above for high level description/secondary subject!)
Update/Edit 2014-06-29
Although it might seem like a duplicate, it doesn't look like it. For one, it doesn't address the images as available/aliased in a resourcedictionary, and another point includes I can't get it to work... :)
As indicated at the top of the post, here is the complete system & where I am with what @Clemens posted a year ago in what is thought by him to be a duplicate:
Note: Don't be confused. I am _hoping_ it really is a dupe, and I can just post here a complete working solution. It's been too many hours tweking all parameters with virtually nothing on the canvas. So please feel free to make it work! :)
The Card() class is just properties-nothing more. Here it is with the parts I've been trying to get to work:
Public Class Card
Public Property Left As Double
Public Property Top As Double
Public Property Width As Integer ' of card in pixels
Public Property Height As Integer ' of card in pixels
Public Property Source As String ' path to image
Public Property SourceImage As Image ' image as an Image()
End Class
Next is the XAML itself (constantly being added/to/edited):
<Window x:Class="MainWindow" x:Name="CardTable"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Solitaire" Height="843" Width="997">
<Grid>
<Viewbox>
<Grid Height="584">
<Canvas x:Name="TheCanvas" HorizontalAlignment="Left" Height="564"
Margin="10,10,0,0" VerticalAlignment="Top" Width="688"
>
<ItemsControl ItemsSource="{Binding Source=TheCards}" Width="300" Height="400" Background="Azure">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Source}" Width="{Binding Width}" Height="{Binding Height}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
</Viewbox>
</Grid>
</Window>
Finally, the code-behind, which creates the ObservableCollection of Card():
Imports System.Collections.ObjectModel
Class MainWindow
Public Property TheCards As New ObservableCollection(Of Card)()
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Setup()
End Sub
Private Sub Setup()
Dim aCard As Vegas.Card = New Card() With {.Source = "images/queen_of_diamonds.png", .Left = 200, .Top = 150.0, .Width = 125, .Height = 200}
TheCards.Add(aCard)
End Sub
End Class
The resulting WPF Window, when rendered, is a disappointing:
note: If you look carefully, you can see that I put the pointer at the bottom right corner of the azure background, thus showing that at least that showed up...
I hope I've kept this update straight & to the point.
Thank you all again!
Update/Edit 2014-06-30
Error output I just noticed in Immediate Window:
[...]
System.Windows.Data Error: 40 : BindingExpression path error: 'Width' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Width; DataItem='Char' (HashCode=7536755); target element is 'Image' (Name=''); target property is 'Width' (type 'Double')
System.Windows.Data Error: 40 : BindingExpression path error: 'Height' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Height; DataItem='Char' (HashCode=7536755); target element is 'Image' (Name=''); target property is 'Height' (type 'Double')
System.Windows.Data Error: 40 : BindingExpression path error: 'Source' property not found on 'object' ''Char' (HashCode=7536755)'. BindingExpression:Path=Source; DataItem='Char' (HashCode=7536755); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource')
[...]
Makes me think they need to be in "<ItemsControl.ItemContainerStyle>" below...:
xmlns:proj="clr-namespace:Vegas"
[...]
<Grid>
<Viewbox>
<Grid Height="584">
<Canvas x:Name="TheCanvas" HorizontalAlignment="Left" Height="564"
Margin="10,10,0,0" VerticalAlignment="Top" Width="688"
>
<ItemsControl ItemsSource="{Binding Source=TheCards}"
Width="300"
Height="400"
Background="Pink">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type proj:Card}">
<Image Source="{Binding Source}"
Width="{Binding Width}"
Height="{Binding Height}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style x:Name="CardStyle">
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Canvas>
</Grid>
Thank you very much in advance for any answers, solutions, or insights. I just want this display framework for the card table done so I can move on to the fun part of programming the code-behind! :)