How to bind a Canvas to a collection of items in Silverlight
Background
I've got a collection of objects which I want to draw on a canvas. Each of these object has a DateTime property, which determines the position of that object along the x-axis on the canvas. Each object also has some other properties which determine the image that need to be drawn on the canvas. The most important feature that I want to implement is that as time passes by the second, these images representing the objects would move along the x-axis. In other words, the right vertical boundary of the canvas would always represent the current time (e.g. DateTime.Now), and objects in the collection would need to update their position on the canvas relative to that boundary. I am very new to Silverlight and hence I have quite a few questions including the following. In addition, I also have the requirement to follow the MVVM framework.
Questions
What should I use in the XAML to achive the above? I thought about using ItemsControl with Canvas as the Panel, but I am not sure how to do it or even whether it is the best way. Any actual XAML code would be great.
How should I bind the collection of objects to the canvas? And if so, how do I move them along the x-axis as time passes? That is, I would like the canvas to update whenever:
- there are objects added to the collection; or
- objects removed from the collection; or
- existing object changing (e.g. some property changed and hence need to change the image that get shown on the canvas) in the collection; or
- even if there are no changes to the collection as mentioned above, these objects will need to move ever开发者_Python百科y second.
Sorry if I have use the wrong terms for anything as I am still new to Silverlight.
Thanks.
I know this question is a little old, but you can just use a render transform - I'm doing something similar;
<ItemsControl ItemsSource="{Binding Notes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="{Binding W}" Height="{Binding H}" BorderBrush="Navy" BorderThickness="5" CornerRadius="10">
<TextBlock Text="{Binding Text}"/>
<Border.RenderTransform>
<TransformGroup>
<... elided ...>
<TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
</TransformGroup>
</Border.RenderTransform>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you really want to use MVVM and data-binding, then an ItemsControl with the ItemsPanel defined as a Canvas might just work. Bind the ItemsControl.ItemsSource to an ObservableCollection in your VM. In your ItemTemplate for the ItemsControl, bind the UI item element's Canvas.X and Canvas.Y to your data items, using an IValueConverter in between to do the mapping of DateTime to X coord, etc...
Something like this:
<ItemsControl ItemsSource="{Binding Path=MyItemsInVM, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="50" Height="50" Canvas.Left="{Binding Path=MyDateTimeProperty, Converter={StaticResource DateTimeToLeftOffsetConverter}}" Canvas.Top="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Another approach is using the Model-View-Presenter pattern. MVVM is not the only show in town. When you have the need to do a lot of UI manipulation, or work with the VSM, then a Presenter can be a better fit (although Behaviors can also play an important role).
You can set up a timer in your presenter that operates at your refresh interval, and in the Presenter just handle the timer event to iterate over the collection and map objects to (X,Y) positions, updating the UI elements directly.
精彩评论