Binding several ItemsControl to one ObservableCollection - wpf

I have two tabs.
The code of both tabs is in the same XAML file (yes, it must be)
Each tab references the same ObservableCollection
<ItemsControl ItemsSource="{Binding ConnectorItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Depending on the tab, the collection is reloaded and contains other data
The problem is that it only displays in the last tab.
I know that this results from logical parents but I am looking for a solution in this situation
If I had a bookmark code in a separate XAML it would not be a problem but I can not use it

Related

How does ItemsControl remember its focused element?

Consider the following layout:
<Button Grid.Row="0">Before</Button>
<ItemsControl x:Name="MainItemsControl"
Grid.Row="1"
KeyboardNavigation.TabNavigation="Once"
KeyboardNavigation.DirectionalNavigation="Contained"
IsTabStop="False">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBoxItem>Test1</ListBoxItem>
<ListBoxItem>Test2</ListBoxItem>
<ListBoxItem>Test3</ListBoxItem>
</ItemsControl>
<Button Grid.Row="2">After</Button>
With regards to keyboard navigation, this works as you would expect:
With three <Tab>s, you can navigate from the first button to the itemscontrol and finally to the second button.
When tabbing into the ItemsControl, you can use cursor keys to navigate the contained items
When tabbing out of the ItemsControl and back into it, the last focused item is restored
Now, let's replace the ListBoxItems with another level of ItemsControls:
<ItemsControl x:Name="MainItemsControl"
[...]
<ItemsControl KeyboardNavigation.TabNavigation="Once"
KeyboardNavigation.DirectionalNavigation="Continue"
IsTabStop="False">
<ListBoxItem>One1</ListBoxItem>
<ListBoxItem>One2</ListBoxItem>
<ListBoxItem>One3</ListBoxItem>
</ItemsControl>
<ItemsControl KeyboardNavigation.TabNavigation="Once"
KeyboardNavigation.DirectionalNavigation="Continue"
IsTabStop="False">
<ListBoxItem>Two1</ListBoxItem>
<ListBoxItem>Two2</ListBoxItem>
<ListBoxItem>Two3</ListBoxItem>
</ItemsControl>
</ItemsControl>
By and large, this still works as desired. You now can use left+right arrow keys to navigate between "One" and "Two" items.
However, when I focus a "Two" item, then tab out of the ItemsControl and back into it, the focus of the last selected "One" item (i.e. the last focus of the leftmost inner ItemsControl) is restored.
What kind of mechanism causes the the ItemsControl to remember its inner focus and why does it break when I add another layer of ItemsControls inside?
(Note: No manual FocusScopes or the like are defined so far. By tinkering with FocusManager, you can make WPF restore the correct focus. I am wondering about the vanilla default behavior.)

Dynamically show a different amount (0-10) BitmapImages on a View

I have a small problem designing problem:
My card tool should display 0-10 images on my view.
Sometime just three, sometimes six, sometimes all ten...
Due to MVVM I don't want to just Controls.Add() the images to the grids/controls content.
What is a good approach to this? One way would be having ten bitmap variables, but is there another better way?
Edit:\
I tried it like that:
<ItemsControl ItemsSource="{Binding CardImages}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Stretch="Uniform" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But its not working as it should.
I have SIX pictures, but the rest of the pictures arent visibilty (out of sigth). I want to show all of the pictures, so the 3 have to be about 50 % smaller in height and the other three atm not visible pictures should be shown under the shown three pictures. Hope thats clear.
How to solve that? I tried ScrollViewers, ViewBoxes and some different kind of templates / panels, but had no sucess. :(
I would bind an ItemsControl to a public observable collection property that contains your image sources / locations / however you reference them on your view model and then template the items to display images.
<ItemsControl Binding="{Binding MyPublicProperty}">
<ItemsControl.ItemTemplate>
<Image Source="{Binding Source={StaticResource MyImage}, Path=Source}"/>
</ItemsControl.ItemTemplate>
</ItemsControl>
See this SO question for binding the image.

ListView with Rows and Columns

I have a ListView in WPF. I have an ObservableCollection as the ItemsSource. I want the items to simply flow from left to right and then onto the next row left to right etc. Image a Windows Explorer in Large Icon mode where you see the folders and files as large icons in a grid.
I am using a third party component that is based on the ListView, so I have to use ListView methods to make this work.
How do I do it?
Update: Here is my code using the answer given:
<diag:NodeListView Name="nodeListViewSources" Width="400" Margin="0,0,0,0" Background="Gray" SelectionMode="Single" SelectionChanged="nodeListView_SelectionChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</diag:NodeListView>
The NodeListView is a third party class derived from a ListView. Maybe that is the problem, but I thought it should work the same.
You just need to change the items' panel to a WrapPanel.
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
I was able to get a hold of the third party component vendor. Turns out I also needed to add the following:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
This along with the WrapPanel worked. Thanks to all...

showing different user controls - WPF MVVM

I created a dbml file, which automatically created the designer.cs
In the designer.cs (which is the Model in the MVVM) there are two different classes in the database:
ElementA and ElementB.
I have two user controls:
Element_A_UserControl - displays a single instance of ElementA
Element_B_UserControl - displays a single instance of ElementB
There is another user control that has two stack panels.
The first stack panel displays a list of Element_A_UserControl
The second stack panel displays a list of Element_B_UserControl
Here is the stack panel #1 XAML:
<StackPanel>
<ItemsControl ItemsSource="{Binding AllElements_A}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<vw:Element_A_UserControl x:Name="elementA">
</vw:Element_A_UserControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Here is the stack panel #2 XAML:
<StackPanel>
<ItemsControl ItemsSource="{Binding AllElements_B}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<vw:Element_B_UserControl x:Name="elementB">
</vw:Element_B_UserControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Up to now everything works fine.
I want to have one stack panel, which displays a list of ElementA or a list of ElementB depending of a condition.
Note: The property to get list of elements is different.
i.e.
ItemsSource="{Binding AllElements_A}
ItemsSource="{Binding AllElements_B}
I hope that my question is clear enough.
Dazy.
One way is that you could try to use a conditional DataTemplate. Something like this:
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:ElementAType}">
<vw:Element_A_UserControl x:Name="elementA">
</vw:Element_A_UserControl>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ElementBType}">
<vw:Element_B_UserControl x:Name="elementB">
</vw:Element_B_UserControl>
</DataTemplate>
</ItemsControl.Resources>
Then, in your viewmodel, create:
public ObservableCollection<object> CombinedCollection {get; set;}
and load it with either of your collections conditionally.
Alternatively, keep both ItemsControls in your XAML, and conditionally hide/show them using Visibility and a BooleanToVisibilityConverter. Given these two choices, I would likely choose this one, as it is clearer in the code, and easier to maintain than the conditional DataTemplate above. However, you seemed to indicate that you didn't want to do that, so I presented the first one as an option.

Image binding works in Image not in ItemsControl

I am a bit baffled here. I have a List<BitmapImage> in a Viewmodel that is populating. I am trying to display the list on the view with an ItemsControl, but the Images don't show up. Oddly, I can access the same collection and get an image to display if I am using an Image tag.
<ItemsControl ItemsSource="{Binding Path=Images}" MinHeight="80">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" MinWidth="80" MinHeight="80" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Image HorizontalAlignment="Left" Name="image1" Stretch="Uniform" VerticalAlignment="Top" Source="{Binding Path=Images[0]}" MinHeight="80" MaxHeight="200" />
Note that they both point to Images. The Image shows up, the ItemsControl stays empty. What is going on?
You'll solve this by using an ObservableCollection as opposed to a List. The ItemsControl isn't going to rebind on the change notification of a List. You won't have to worry about explicitly calling the change notification for the List either if you use an ObservableCollection.
I was able to replicate your scenario and simply using an ObservableCollection solves the issue. As to why: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Specifically, see this quote in the Remarks section:
For change notification to occur in a binding between a bound client and a data source, your bound type should either: Implement the INotifyPropertyChanged interface (preferred). Provide a change event for each property of the bound type. Do not do both.

Resources