I have a ListBox bound to an ObservableCollection:
<ListBox ItemsSource="{Binding ObservableCollectionOfFoos}" />
The ObservableCollection contains instances of Foo, Foo implements INotifyPropertyChanged.
I'm trying to bind properties of the ListBoxItems to properties of Foo.
Here is what I tried:
<DataTemplate DataType="{x:Type local:Foo}" >
<TextBlock Content="{Binding PropertyOfFoo}" Background="{Binding AnotherPropertyOfFoo}"/>
</DataTemplate>
this works, but, the problem is that I only have access to the properties of the TextBlock and not the containing ListBoxItem, so, for example, Background only changes the color around the text and not the whole entry. I have a feeling I'm using the wrong tool for the job here.
a point in the right direction would be very appreciated.
The DataTemplate specifies the template (UI presentation) of the content of the list box item. What you need to style is the item container itself which can be done via the ItemContainerStyle property of the ListBox.
Related
so my question is: How can the view link to the view model if we use Data Template?
<DataTemplate DataType="{x:Type my:PersonViewModel}">
<my:PersonView/>
</DataTemplate>
Because, I thought that the Data Template is just to define the visual structure of a data object (in this case is a view model). So how can the view know its viewmodel is an item in the list ? Thank you.
The DataType property is used as a key to automatically select a DataTemplate that matches the type of the Content object of a ContentControl or ContentPresenter.
Since a ContentControl or ContentPresenter is used as "item container" for the items in an ItemsControl, it would also automatically select a matching DataTemplate.
However, you won't typically utilize automatic DataTemplate selection in an ItemsControl, but instead directly set the ItemTemplate property:
<ItemsControl ItemsSource="{Binding Persons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<my:PersonView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The value of the DataContext property of the elements inside the DataTemplate is then provided by property value inheritance from the ContentControl or ContentPresenter.
I have little problem with binding. I have stackpanel in my xaml which has some elements in children collection. Second i have textblock which shows count of elements in stackpanel. It is done by binding that way
<TextBlock Text="{Binding Children.Count, ElementName=CommentsContainer, Mode=OneWay, StringFormat=({0})}" />
<StackPanel x:Name="CommentsContainer"></StackPanel>
It works fine for first-time but if is something added to stackpanel children collection dinamically textblock text is not updated. I mean that collection count does not implement inotifypropertychange, but how do something like this properly?
You asked "how [to] do something like this properly". The WPF way of doing it would be to have a collection of items implemented as a property on your Window or ViewModel or whatever, then bind an ItemsControl to that collection.
For example, if you had a collection of strings:
public ObservableCollection<string> MyItems { get; private set; }
// elsewhere in the same class...
MyItems = new ObservableCollection<string>();
MyItems.Add("first");
MyItems.Add("second");
MyItems.Add("etc");
ObservableCollection<T> is a good collection class to use for WPF as notification of any changes made to the collection (such as adding or removing items) will be pushed to any observers of the collection (such as WPF's binding system).
To see these items in your View (eg. Window, UserControl, etc), you would use a control that can display a list of items (one derived from ItemsControl) and bind that control to the list property, like so:
<Window ... >
<StackPanel>
<ItemsControl ItemsSource="{Binding MyItems}" />
<TextBlock Text="{Binding MyItems.Count}" />
</StackPanel>
</Window>
ObservableCollection<T> does implement INotifyPropertyChanged so the Count property will always reflect the actual number of items in the list.
You don't have to have a list of strings of course, they could be any kind of object. Similarly, you don't have to use an ItemsControl but could use something like a ListBox or ListView instead (they both derive from that base control class). Furthermore, you might want to look into data templating as this can be used to change the visual appearance of the items in the ItemsControl.
I have a custom control ListItem. I need to display five such items in a window and these items could change during runtime; items could be added or deleted, or content could change in ListItem.
ListBox appears to be a good solution to display items. But what I have seen is we can add items and style them, and can handle updates with data trigger.
myListBox.Items.Add(new { FileName = "SomeFile", State="Uploaded" });
But we can not do something like
ListItem curItem = new ListItem();
myListBox.Items.Add(new { curItem });
Even if I do it shows empty item in the list.
So if I want to add my custom control to some listbox, how could that be possible. That is using ListBox just as a container so we can get away from the pain of positioning and all that after list changes. Or is there a better way to do that?
You are in luck - this is the bread and butter of WPF! Set the ItemsSource of your ListBox (possible in XAML or cs):
myListBox.ItemsSource = myEnumerableCollection;
or
<ListBox ItemsSource="{Binding MyItemsProperty}">
Use a DataTemplate (you do not need a UserControl) to style each item in XAML:
<ListBox ItemsSource="{Binding MyItemsProperty}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FileName}"/>
<TextBlock Text="{Binding State}"/>
<!--Whatever you want-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If your collection is an ObservableCollection<T> changes to that collection (e.g. items added or removed) will be reflected in the ListBox automatically. If T implements INotifyPropertyChanged changes to properties on each item will also automatically show up on the UI.
For more see the WPF Binding Overview.
Don't create or manipulate UI elements in procedural code in WPF.
<ListBox ItemsSource="{Binding SomeCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<my:MyControl/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
where my:MyControl is a UserControl with whatever UI you want.
Basically, I have a list of colors and a defined datatemplate for listbox item:
<DataTemplate x:Key="colorItemDataTemplate">
<Border x:Name="borderInner" BorderBrush="Black" BorderThickness="1" Background="{Binding Brush}" Width="11" Height="11" />
</DataTemplate>
Now, when I add a bunch of items into the listbox and then set the ListBox.ItemsSource property to my List, the listbox is filled correctly.
There is also a slider with its appropriate event handler. Within the event handler, Brush property of one of the items from the listbox is changed. Since the appearance of the item depends on the Brush Property, listbox should reflect the change.
I could reset the ItemsSource property, but then all items have their templates applied and with more than 200 items in the listbox, this is pretty slow.
So, is there any way to refresh the template for only one item from the listbox?
Thanx
I'm not sure I follow. If you've bound the Background to the property, changing the property should automatically udpate the background of the ListBoxItem. If you're not seeing that, make sure you are either using a DependencyProperty or implementing INotifyPropertyChanged.
You could use a binding converter. In the converter class you could have some logic like
(pseudo-code)
if (ListBoxItem.IsSelected)
return SpecialColorFromSlider
else
return NormalListBoxColor
I got a TreeView containing different objects from different classes. Now I want to build a propertypanel, which shows up different content, depenting on what object/class is selected in the TreeView. What is the best way to build such panel? Differnt panels and collapsing panels depending on the selection(Whould make implementing the ObserverPattern this easier for me?)? Or an other approach?
I would bind the property panel (which could be just a ContentControl) to the SelectedItem in the TreeView:
<ContentPanel Content="{Binding SelectedItem, ElementName=_treeView}"/>
Then I would use DataTemplates to show the correct panel for each class of item you have:
<DataTemplate DataType="{x:Type local:SomeClass}">
<Label>This is displayed for SomeClass</Label>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SomeOtherClass}">
<Label>This is displayed for SomeOtherClass</Label>
</DataTemplate>
Obviously your DataTemplates can be as complex as needed to display the various classes present in the TreeView.
Do you mean a property grid?