How can I bind Image control to ListBox dynamically? - wpf

I want to implement a ListBox which each item include a Image control and some other controls, then use it to binding some data. Due to this ListBox need to contains more than 2000 items, this means I have to do some optimization for it.
First, I noticed that most of the Image controls has one same picture(Default avatar), so I create a singleton ImageSource-object for the data. But although the Image control's source is the same object, you know I also need to create 2000 Image control in the ListBox with DataTemplate below:
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Avatar}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is there have a way to reduce Image control object's number in my program? Thank you!

Related

Binding to two dependency properties of the user control which is a ListViewItem

I've created an user control which is a ListViewItem. That control has 2 dependency properties I would like to bind to from my ViewModel. But how am I supposed to do that when I can only bind one thing (collection) to ListView ItemsSource property? How can I bind to ExpanderInfo dependency property? Is there any way to do that or maybe I have made a bad assumption and should have created user control in other way?
Here is my xaml code:
<ListView ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask}" Height="200" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
Thank you for your help!
Replace <tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/> with
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding DataContext.ExpanderStatus, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"/>

Adding a small popup on a wpf listbox that is already using itemsource

Here is a portion of my wpf-xaml code :
<ListBox x:Name="TestJobSuiteListBox" Grid.Row="1" ItemsSource="{Binding AvailableJobs}" MouseRightButtonDown="TestJobSuiteListBox_OnMouseRightButtonDown">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<ListBoxItem Content="{Binding Name}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I would like to add another listboxitem to that ListBox and I dont want it to be visible before you rightclick on the listbox. It also should not be bound to the "AvailableJobs" property.
Something like this :
<ListBox x:Name="TestJobSuiteListBox" Grid.Row="1" ItemsSource="{Binding AvailableJobs}" MouseRightButtonDown="TestJobSuiteListBox_OnMouseRightButtonDown">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<ListBoxItem Content="{Binding Name}"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
<ListBoxItem x:Name="AddJobbListBoxItem" Visibility="Hidden"></ListBoxItem>
</ListBox>
This doesn't work, because of "itemsource must be empty problem"
Anyone have a good Idea of how I could do it ?
I don't need help with the visibility/rightclick functionality.
Thanks in advance, I hope the problem is understandable.
You can put listbox to stackPanel, and disable it's scrolling. Then add that one element also to the stackPanel under the listbox, and finally add that stackPanel to scrollViewer. Then you have listbox with AddButton.
<ScrollViewer>
<StackPanel>
<ListBox ItemsSource="{Binding AvailableJobs}"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<!-- ... -->
</ListBox>
<Button x:Name="AddJobbButton" Visibility="Collapsed" />
</StackPanel>
</ScrollViewer>
Notice that if you have lots of items in listbox, there might be some performance problems, because I'm not sure that listbox's virtualizing is working correctly if it's in stackPanel.
EDIT: of course you have to listen mouse events and set then button's visibility to visible and so on...
I think you have to use ItemTemplateSelector to achieve this functionality. You can create different DataTemplate as per your requirement in the Resources section and bind properly in the xaml. Check the answer here, it will give you the idea about the approach. Please refer this examlpe also. Hope this will help.

Getting ScrollViewer.VerticalOffset from ListBox in PivotControl

I have a PivotControl that contains ListBox elements:
<controls:Pivot Title="SECTIONS" x:Name="pivotControl" ItemsSource="{Binding SectionViewModels}">
<controls:Pivot.HeaderTemplate>
<!-- -->
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- if you don't explicitly specify the height, the scrolling won't work -->
<ListBox ItemsSource="{Binding StoryViewModels}" SelectionChanged="StoryList_SelectionChanged"
Height="625" u:ScrollViewerMonitor.AtEndCommand="{Binding ElementName=LayoutRoot, Path=DataContext.FetchMoreDataCommand}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:StoryControl />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
I want to get and set the ScrollViewer.VerticalOffset of a ListBox corresponding to a given SectionViewModel (which is the item source of the pivot control). How can I do this?
There're some cases that you need to access view elements. For those cases using the VisualTreeHelper is the solution. You can find a summary of it in my blog and some helper extension methods.
I recommend to use SilverlightSpy to see how the VisualTree is composed at runtime and be able to more efficiently navigate it.

How can I achieve a binding path which is bound by another binding?

I'm writing my own UserControl which displays data in a ListBox. I want to achieve something similar to a property like "DisplayMemberPath". In my example, it's "EditableMemberPath", which should determine which member will be displayed in the textbox. However, using a binding on a binding does not work.
<ListBox ItemsSource="{Binding Path=Items, ElementName=me}"
SelectedItem="{Binding Path=SelectedItem, ElementName=me}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Converter={Binding Path=ItemToImageConverter, ElementName=me}}" />
<TextBlock Text="{Binding Path={Binding Path=EditableMemberPath, ElementName=me}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Can you help me finding a proper solution?
Best Regards
Oliver Hanappi
You can't do that directly in XAML (at least not with the built-in classes) : a Binding is not a DependencyObject, so you can't bind its properties.
However the post mentioned by Martin Harris looks promising...

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