Render List<Canvas> as list items (or itemscontrol) - silverlight

I've effectively got a List or a List, XAML that represents the canvas elements... as a return from some stuff I have no control of.
I've been moderately successful rendering via stackpanel.children.add etc, however want to start having the list of canvas within a virtualizing panel or list.
I've set itemssource and datacontext on the <ItemsControl> and set the <DataTemplate> as such
<DataTemplate>
<ContentControl content="{Binding Path=CanvasBody}"/>
</DataTemplate>
This effectively turns entire silverlight body white/blank. I dont really care how I ultimately get to the desired result which is a list of the rendered canvas's... preferably virtualized for speed.
Its a retarded problem, and not ideal as far as how silverlight apps are built, I know...
I'd really appreciate any pointers. THANKS!

Generally to display a list of elements you bind the items control itemssource property to the list and then set a datatemplate for it which displays the desired properties of the list item type. You dont need to set content control. Beyond that I cant see what exactly you are asking.
<DataTemplate>
<Grid>
<TextBlock Text="{Binding ExampleProperty1}"/>
</Grid>
</DataTemplate>
codebehind file:
public class ExampleClass
{
public String ExampleProperty1
{
get
{
return "TEST";
}
}
}
public List<ExampleClass> List {get;} // note that this must be a public PROPERTY,
// not a field!

Related

Binding ObservableCollection of strings to templated ListBox

I have this collection
ObservableCollection<string> Urls { get; set; }
inside my data context class. I have a binding to it in my list box:
<ListBox ItemsSource="{Binding Urls}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding .}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The data is diplayed in the list box, the two corresponding-not-shown-here buttons with commands Add and Delete work as well, however, the changing the TextBox does not affect the contents of the collection.
I have tried Mode=TwoWay in binding, but I figured that it is turned on already. I have tried some other options like Validate=OnPropertyChange, however, there is still nothing get updated.
How to make the TextBox inside that templated items in ListBox actually update the Urls property of a datacontext class?
You cannot modify strings; use a wrapper class with one string property, then bind the TextBox to said property. That way the strings in the property can be replaced with the edited ones.

binding to observable collection silverlight 4, grid

Can I bind a simple 'grid' to an observable collection? So i have a grid with just one column and several rows. The rows get populated at runtime with some hyperlinks which can get deleted/added etc. I don't want to write functions to add/remove them from the grid everytime and would prefer to use an observable collection and let the grid update itself. Can a simple grid do that ? i tried but it didn't even compile.
Thanks
[EDIT] Solved. The marked answer is correct [/EDIT]
Other answers cover various bases but your specific requirement is filled by the ItemsControl. You would probably want to contain it in ScrollViewer just in case where you have more links than can be seen at one time. You would have markup something like this:-
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyObsCollectionOfUrlInfo">
<ItemsControl.ItemTemplate>
<DataTemplate>
<HyperLinkButton NavigateUri={Binding Uri} Content={Binding Title} />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Your observable collection would contain a list of objects of a type like:-
public class UrlInfo
{
public Uri Uri {get; set; }
public string Title {get; set; }
}
Silverlight does not support this. You have two options, either use a DataGrid or use the following code that allows you to use a Grid within an ItemsControl which will achieve what you are after.
http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/
#ColinE is correct, you can't bind to a Grid, but you can bind an ObservableCollection to a DataGrid or an ItemsControl.

In WPF how can I restrict the type of children in a Panel?

We want to create a subclass of Canvas that only allows children of a specific type (they need to have intimate knowledge of our subclass and vice-versa.) That said, is there any way to force a panel to only accept children of a certain type (or types)?
M
The solution we came up with was to simply subclass the Canvas, then monitor the children. If one is added that's not of the type we want, we instantly remove it and throw an error. Won't stop compile-time errors but does the trick.
Extending this further I was thinking about also subclassing the canvas, then Newing over the Children property to return our own collection which we've internally synced to the panel's children via binding. That way we can also have compile-time support. Granted if someone casts our subclass to a straight canvas, then obviously the 'new'd Children property won't be accessed (its a 'new' not an override) but the aforementioned collection monitoring will still give us what we want.
It would have been nice if the WPF team had come up with a generic canvas so we could do something like canvas but that obviously wouldn't work in XAML unless they somehow came up with syntax for that. Then again, a canvas is pretty damn basic so maybe we'll just roll our own geeneric version where we could do something like this...
public class TypedCanvas<t> : PanelBase
{
// Implementation here
}
public class FooCanvas : TypedCanvas<Foo>{}
public class LaaCanvas : TypedCanvas<Laa>{}
...of which we could then use FooCanvas and LaaCanvas via XAML while still getting all the benefits of using generics.
Even better, make it TypedPanelBase so we could use it with any other custom panel as the base type.
Actually, now that I've typed this... I think I'm about to go re-write our canvas to try this approach! (Either way, I now have a solution which is what we were after.)
Actually... no way.
Besides, I don't understand your goals. If you need to work with some specific containers just cast Panel.InternalChildren:
this.InternalChildren.OfType<MyType>().Do(...);
Consider about scenario: you have a collection of strings, which is the source for ItemsControl. In DataTemplate we have button which content is binded to item from mentioned collection. And ItemsControl.ItemsPanel is Canvas.
public IEnumerable<string> Items
{
get;
}
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
So, what items types do you want to restrict? Buttons or strings?
The problem in this scenario is that ContentPresenters will be effective visual children of Canvas. But in overriden method OnVisualChildrenChanged (where you could try to check item type) Content and ContentTemplate properties are set to null due to deferred binding.
So the one acceptable solution I can propose is creating your own ItemsControl, which returns some concrete container instead of ContentPresenter:
public class MyItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new Button();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is Button;
}
}
<self:MyItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<self:MyPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</self:MyItemsControl>
With this approach, you guarantee that your item containers (Panel.InternalChilder) are buttons (or something) and in MyPanel you could safely cast:
this.InternalChildren.Cast<Button>()

What techniques can I employ to create a series of UI Elements from a collection of objects using WPF?

I'm new to WPF and before I dive in solving a problem in completely the wrong way I was wondering if WPF is clever enough to handle something for me.
Imagine I have a collection containing objects. Each object is of the same known type and has two parameters. Name (a string) and Picked (a boolean).
The collection will be populated at run time.
I would like to build up a UI element at run time that will represent this collection as a series of checkboxes. I want the Picked parameter of any given object in the collection updated if the user changes the selected state of the checkbox.
To me, the answer is simple. I iterate accross the collection and create a new checkbox for each object, dynamically wiring up a ValueChanged event to capture when Picked should be changed.
It has occured to me, however, that I may be able to harness some unknown feature of WPF to do this better (or "properly"). For example, could data binding be employed here?
I would be very interested in anyone's thoughts.
Thanks,
E
FootNote: The structure of the collection can be changed completely to better fit any chosen solution but ultimately I will always start from, and end with, some list of string and boolean pairs.
I would strongly recommend the ItemsControl, its behaviour is as close as you can get to the ASP.Net repeater control so it is very flexible.
Declare the item control as:
<ItemsControl Name="YourItemsControl"
ItemsSource="{Binding Path=YourCollection}"
ItemTemplate="{StaticResource YourTemplate}">
</ItemsControl>
Then you can use the datatemplate to organise the data into a display format for the user
<DataTemplate x:Key="ProjectsTemplate">
<StackPanel Margin="0,0,0,10">
<Border CornerRadius="2,2,0,0" Background="{StaticResource ItemGradient}" d:LayoutOverrides="Width, Height">
<local:ItemContentsUserControl Height="30"/>
</Border>
...
Useful ItemsControl Links
http://drwpf.com/blog/itemscontrol-a-to-z/
http://www.galasoft.ch/mydotnet/articles/article-2007041201.aspx
I hope this helps you.
You can use Data Templates. Here's a good post about it.
This is exactly the kind of scenario WPF simplifies. Event-handlers- bah! Data-binding and data templates make this a cinch. I have constructed an example illustrating how you can do this.
Here is the code-behind, which declares a class to represent your items- PickedItem. I then create a collection of these items and populate it with some samples.
public partial class DataBoundCollection : Window
{
public DataBoundCollection()
{
Items = new ObservableCollection<PickedItem>();
Items.Add(new PickedItem("Item 1"));
Items.Add(new PickedItem("Item 2"));
Items.Add(new PickedItem("Item 3"));
InitializeComponent();
}
public ObservableCollection<PickedItem> Items
{
get;
set;
}
}
public class PickedItem
{
public PickedItem(string name)
{
Name = name;
Picked = false;
}
public string Name
{
get;
set;
}
public bool Picked
{
get;
set;
}
}
Now, let's look at the XAML mark-up for this window:
<Window x:Class="TestWpfApplication.DataBoundCollection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBoundCollection" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Picked}" Margin="5"/>
<TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I create a ListBox to hold the items, and bind its ItemsSource property to the collection I created in the code-behind. Then, I provide the ListBox with an ItemTemplate, which determines how each PickedItem will be rendered. The DataTemplate in this case is as simple as a check-box and some text, both bound to the member variables on PickedItem. Now, when I check any of these items, the data in the underlying collection is modified, in real-time, with no event handlers needed. Ta-da!
alt text http://img405.imageshack.us/img405/1083/databoundcollection.png

MVVM ListBox controlling a Content Control

I've been going round in circles with this for a couple of days, and I'm hoping a WPF guru can see where I'm going wrong.
I'm setting CurrentViewModel in code. The Selected item of my ListBox and the Content of my ContentControl bind correctly. But when changing the selected item in the Listbox via the UI the CurrentViewModel is being set but the Content Control is not being updated.
I'm using a data template to map my Views and View Models.
<DataTemplate DataType="{x:Type ViewModel:MyViewModel}">
<View:MyView />
</DataTemplate>
I have a ListBox which is bound to an observable collection of ViewModels. The Selected Item is bound to the current view model.
<ListBox ItemsSource="{Binding MyViewModelCollection}" DisplayMemberPath="DisplayName" SelectedItem="{Binding CurrentViewModel, Mode=TwoWay}"/>
I also have a content control that is also bound to the CurrentView Model
<ContentControl Content="{Binding CurrentViewModel, Mode=TwoWay}"/>
This is the property that they are both bound to
public MyViewModel CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel== value) return;
_currentViewModel= value;
OnPropertyChanged("CurrentViewModel");
}
}
I've edited the names for clarity and removed formatting information.
Any help greatly appreciated.
Cheers,
Daniel
EDIT: Came across the link How can I debug WPF bindings?. I set a break point on the Content binding and it does indeed only get called once when the binding is first set.
You should not be setting TwoWay as the mode on your ContentControl:
<ContentControl Content="{Binding CurrentViewModel, Mode=OneWay}"/>
This is because you intend your ContentControl to read the value, but never write it.
As an aside, you can also bind the ContentControl to the currently selected item in the collection, rather than to that property by doing this:
<ListBox ItemsSource="{Binding MyViewModelCollection}"
DisplayMemberPath="DisplayName"
IsSynchronizedWithCurrentItem="True"/>
<ContentControl Content="{Binding MyViewModelCollection/}"/>
The "slash" (/) at the end of the collection indicates the current item selected in the collection and setting that current item property is as simple as setting the IsSynchronizedWithCurrentItem equal to true.
A lot of times I find with this combination, I really don't need the extra property on my view model.
Anyway, I hope this helps.

Resources