Bound String List displays containing class name not the string - wpf

My Problem is the following:
I have a class which has a ObservableCollection of strings, which gets populated by the selected children.
Those are supposed to be listed in a ListBox.
But the strings aren't listed, rather the object type in FilterList is shown.
<ListBox Grid.Row="2" Grid.Column="0"
ItemsSource="{Binding FilterList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ListOfActiveFilters}">
<!--<ContentPresenter Content="{Binding ListOfActiveFilters.}"/>-->
<TextBlock Text="{Binding}" />
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Filter List contains the classes which have ListOfActiveFilters as a Property.
I thought that it would work the way I showed it, but it doesn't.
Since that is also the way I saw others do it.
If I were to use a Class with a single string Property as the type of the Collection instead of the Collection of strings I have right now, I think it would work.
I just don't really see the point in creating a class which holds a string property just so that I can bind the ContentPresenter or TextBox to that property.
What am I doing wrong? I am rather new to the topic.

One single ListBox will only be able to display the filters in one single ListOfActiveFilters collection. You could use nested ItemsControls to display them all:
<ItemsControl ItemsSource="{Binding FilterList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding ListOfActiveFilters}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The other option is to modify your data model and put all strings in a single collection. You could then bind the ItemsSource property of the ListBox directly to this one. But a ListBox itself has no concept of hierarhical data.

Related

WPF DataTemplate for Collection

I must now hang my head, for I have scoured the Google for hours and still have no clue what I'm doing wrong.
<DataTemplate DataType="{x:Type local:Controllers}">
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Path=Port}" />
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
What I'm trying to do is to display an arbitrary number of controller objects in this list. "Controllers" is just an alias for "List<Controller>". "Port" is a property of each "Controller" object, but of course that's not showing up on the list. Items are being correctly added to the collection the list is based on (the collection is actually stored as the Content property of the ContentControl that is displaying this collection of objects), but no item in the collection itself is being displayed.
I thought at first that it might be an update issue--that the collection was being correctly displayed in its initial, empty state, but that isn't the case; if I start with the collection already populated, I still get no items.
Help me, Obi Wan. :(
You need to bind something to the ListBox. That something is just {Binding}, which refers to the instance of the DataTemplates DataType that is passed in at run-time.
<DataTemplate DataType="{x:Type local:Controllers}">
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Path=Port}" />
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>

How do I wrap content in a WPF ListView?

I have a very simple WPF ListView that I'm using to list blocks of text. I'd like it to scroll vertically, but the text should wrap so that there is no horizontal scroll. All the examples I've seen are overly convoluted DataGridView nesting solutions. This seems like such a simple use-case, however. Here is my current code:
<ListView
Height="Auto"
Width="Auto"
Margin="0"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"/>
I've tried setting the ScrollViewer.HorizontalScrollBarVisibility and HorizontalContentAlignment properties but the text simply runs off the end of the control and doesn't wrap.
Each item is added to the ListView.Items collection and is a ListViewItem object. The text is set to the item's Content property.
Here is the code responsible for adding text times to the list:
ListViewItem item = new ListViewItem();
item.Content = "Item text is set here, but refuses to wrap in list view!";
mLogListView.Items.Add(item);
Thank you.
This should be what you need
<ListView Margin="12,23,309,191"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch" >
<!-- here set the itemTemplate to a TextBlock that can wraps-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Note the syntax Text="{Binding Path=.}" that is equivalent to Text="{Binding}". This is called empty binding syntax.
In this case Text is bound to the entire ListViewItem object. The empty binding syntax is useful when you want to bind to the entire object item instead of just to single property of the item.
This is convenient for the example because the source object (the ListViewItem) is of type string and you simply want to bind to the string itself.
For more information see msdn at section Specifying the Path to the Value
I wanted to view images in a ListView, it displays by default only one column. To prevent this, you can insert the following code:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="0" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Now displays ListView, instead of one column, just one line :-(
To prevent this, you can insert this line of code:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
So it could look something like this:
<ListView ItemsSource="{Binding YourItemsSource...}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border ... and so on ...
I hope, it can help someone
;-)

Access property of DataContext inside ItemTemplate

I have a really nasty problem with bindings. I know that there are other topics regarding binding itmes inside itemtemplate to datacontext of an object outside the template. However, this just won't work, i.e. the first textblock display 'Test' as desired whereas the same textbox inside the itemtemplate shows nothing.
<TextBlock Text="{Binding DataContext.Test, ElementName=myList}"/>
<ItemsControl x:Name="myList" ItemsSource="{Binding AllItems}"
Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal"
ItemHeight="170" ItemWidth="140"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image x:Name="{Binding KeyName}"
Source="{Binding ImagePath}"
Width="128"
Height="128">
</Image>
<TextBlock Text="{Binding DataContext.Test, ElementName=myList}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I would appreciate some help here folks as this is really a problem for me.
Inside the itemtemplate, the binding is initialized to the context of the current item in AllItems.
Update
Outside of the ItemTemplateyour bindings are relative to the DataContext of the page.**
Once inside an ItemTemplate then bindings are limited to the scope of the item specifically being evaluated at that time.
So, if we assume the following (based on the code in your question):
<ItemsControl x:Name="myList" ItemsSource="{Binding AllItems}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="tb1"
Text="{Binding DataContext.Test, ElementName=myList}"/>
<TextBlock x:Name="tb2" Text="{Binding KeyName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
tb1 cannot access the DataContext object directly.
tb2 cann access KeyName - assuming that whatever object AllItems is an IEnumerable of contains a property with that name.
As I understand it, inside an itemtemplate, the item past from the enumeration controls the binding source and this can't be overridden (by setting ElementName or otherwise).
If you need the value from Test in every object in your enumeration then you'll need to add it as a property of the object in the enumeration.
I'm sure someone more knowledgeable than me could explain why this is or give a better explanation but that's the gist of it.
** Assuming no other nesting of ItemsControls (or equivalent)

WPF Multiple master/details, same grid

I have a TreeView which has three levels.
Lets say its a league, division and team TreeView.
Now, when I select each of the items in the tree, I would like to see detailed information about it.
Whats the best way to achieve this?
Since Grid doesn't items (like a ListBox), I can't just set its ItemsSource and make a DataTemplate...
I thought about using a ListBox which will contain only the selected item but this seems to be very bad...
Thanks.
You first define the 3 DataTemplates for your league, division and team classes. After, you bind the TreeView to the root of your objects. Your League and Division classes should have a Children property that returns the children. All your classes should have a Name property.
Then when you want to show a single object, use the ContentPresenter, and the bind its content to the SelectedItem if the TreeView.
For example:
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type your_namespace:League}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type your_namespace:Division}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type your_namespace:Team}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
</StackPanel.Resources>
<TreeView x:Name="_tree" ItemsSource="{Binding RootOfYourItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text={Binding Name}/>
</HierarchicalDataTemplate>
</TreeView>
<ContentPresenter Content="{Binding Path=SelectedItem, ElementName=_tree}" />
</StackPanel>
This code was not tested or compiled, it just provided as an example.
I would create a viewmodel with properties for the tree structur, the current selection and the details to the current selection.
The tree struct is one-way bound to the treeview, the SelectedItem from the treeview is OneWayToSource bound to the current selection property (due to the limitations of the property). This property changes the list of child items once the current selection changes, and the child items are bound to the listbox displaying them.

WPF: Problem with ItemsControl datatemplate as a user control

This works fine:
<ItemsControl ItemsSource="{Binding Persons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text="{Binding Path=LastName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But, I want to make use of a User Control in place of the stack panel with two TextBlocks using something like:
<DataTemplate>
<jasControls:NameView/>
</DataTemplate>
But, with this and a million other syntaxes, the NameView shows nothing, yet it works fine in a separate test, outside the ItemsControl, with explicitly set (dependency) property - e.g.
<jasControls:NameView FName="{Binding Path=Person.FirstName}" />
I can find hardly any examples of this anywhere, and need to know how to specify the properties of the user control - or how can the user control 'receive' the individual item type (a Person)? What syntax to use? Do I need to specify the datatype? Is ItemsControl causing a problem or should any similar control do e.g. ListBox? Can I design it so that the user control gets an entire Person object? What dependency properties do I need in the user control? In short, how to get data into the user control?! The actual business types involved will be a bit more complicated involving some logic in the user control, hence my desire to use a user control.
ANY direction on this will be very gratefully received - TIA
Assuming your Persons collection has many Person objects in it, the DataContext property of your NameView control will automatically be set to the Person object.
You wouldn't need any dependency properties to achieve this feat. Your NameView usercontrol would simply be:
<UserControl ...>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</UserControl>
You should have no codebehind to get this information to display.
From there, you should be able to access the Person object from the DataContext property:
Person person = this.DataContext as Person;

Resources