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.
Related
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.
I have a collection of objects that derive from a Person class and I want to bind this collection to the ItemsSource of a ListView.
I want to specify a string to display in the ListView Items. This string will be a composite of properties found on the derived classes.
I also want to bind the SelectedItem of the ListView to a property of type Person in my view model.
As far as I see it I need a string converter for my display string but I'm unsure how to bind to the items within the ItemsSource to generate the composite display string.
Can anyone give me a pointer?
Thanks.
You can either overwrite the ToString() method of your derived classes to return your composite display string, or you can create a Converter like you are suggesting and pass it the entire Item. The converter would then check that the item is of a specified type, and if so compose a string of whatever properties you want.
you dont need the StringConverter, you need DataTemplate
using DataTemplate, you can choose how you would like to display you data as an item in your listBox.
If you could consider your derived class a ViewModel then you could just add a property to that class and then display it in the ListView ItemTemplate. Or like Rachel suggested override your ToString Method and then in your display binding simply write "{Binding}" which will force WPF to call the ToString method
e.g.
public class DerivedPerson : Person
{
public string DisplayString
{
get
{
return string.Format("{0} {1}",FirstName,LastName);
}
}
}
And you xaml:
<ListView ItemsSource="{Binding PersonList}" SelectedItem="{Binding SelectedPerson}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding DisplayString}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I've got a ListBox that contains an alphabetized list of words. For each letter, I'd like the first word to be blue and all other words to be white. I'd done this previously by looping through the words, creating TextBlock controls with the appropriate Foreground color, and adding them manually to the ListBox control. I'd like to do this with databinding, though. Is there an elegant way to apply this sort of conditional formatting with databinding?
This is the sort of thing that you typically use a ViewModel for. What you could do is to create a WordViewModel class that looks something like this (but presumably with INotifyPropertyChanged implementations, etc.):
public class WordViewModel
{
public string Word {get; set;}
public Color ForegroundColor {get; set;}
}
When you add the WordViewModel instances to your ObservableCollection<WordViewModel>, you would then set the appropriate properties based on roughly the same logic you were using before.
Your ListBox would then look something like this:
<ListBox ItemsSource="{Binding MyWords}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Word}" ForegroundColor="{Binding ForegroundColor}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Having a "ForegroundColor" in a Model would of course be a complete violation of the "separation of concerns". It would be most appropriate in a View if there were a clean and easy way to do it. But given the circumstances, unless someone can think of a better way to handle it in XAML, I think it's reasonably appropriate to place it in the ViewModel.
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>()
I'm planning a WPF application which will build dynamic grid with textblocks in the viewmodel and then refresh interface (xaml) with the new grid.
I've done the firts step, but i have problems to refresh the view with the new grid.
Is there any example code of how to bind the grid to the xaml that I can have a look at?? I really can't figure this out!
Thanks
You may be approaching this slightly wrongly, hard to say from the question-
Generally to show a dynamic set of UI elements in MVVM you bind the ItemsSource property of an ItemsControl to an ObservableCollection. The ItemsControl ItemsTemplate property converts the YourViewModel object into a UIElement which can be a TextBlock or whatever style you want.
So as an example:
// model
class Person
{
public string Name {get; private set;}
}
// view model
class MainViewModel
{
public ObservableCollection<Person> People {get; private set;}
}
//view
<UserControl DataContext="{Binding MyMainViewModelObject}">
<ItemsControl ItemsSource="{Binding People}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>/
</ItemsControl.ItemsTemplate>
</ItemsControl>
</UserControl>
I havent tested that code, it is just to illustrate. There are other ways of dissecting the problem into MVVM, it all depends on the situation. You would have to give more details for us to help you out with that. Rarely in WPF is there a need to use code to create or add UI elements to other UIElements etc.
A point to note more along the exact lines of the question however is that an ItemsControl can either bind to a bunch of regular objects and use it's template to create UIElements from them, OR it can bind to a list of UIElements, in which case the template is not applied (sounds like this is the situation you have).