I have a TabControl where the content of each TabItem is a master-details view.
For the master, I'm using a listbox whose ItemsSource is bound to a collection in my ViewModel. Selecting an item from the list displays that particular item's details in a grid off to the side.
When I switch to another tab and then back to the original tab, the listbox selection seems to be lost.
What can I do to maintain the listbox selections in each tab when the tab selection changes?
In normal use the end users will need to 'set up' the detail views the way they like for a particular situation, and then cycle through the tabs occasionally to check on each system (each tab provides details for machinery on a different product line).
The TabControl looks like this:
<TabControl
ItemsSource="{Binding DiagCards}"
ContentTemplate="{StaticResource DiagCardViewTemplate}"
SelectedItem="{Binding SelectedDiagCard}" />
The View for each TabItem has a ListBox that looks like this:
<ListBox
ItemsSource="{Binding DiagCard.DevicesDetected}"
SelectedItem="{Binding SelectedDevice}"/>
The details are displayed in the TabItem using a ContentControl:
<ContentControl
Content="{Binding SelectedDevice}"
ContentTemplateSelector="{StaticResource SelectedDeviceTemplateSelector}"/>
I should note that a simple test using hard-coded TabItems and ListBoxes does seem to maintain the selection when the tab changes:
<TabControl>
<TabItem Header="tab 1">
<ListBox>
<ListBoxItem>
<TextBlock Text="item 1-1"/>
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="item 1-2"/>
</ListBoxItem>
</ListBox>
</TabItem>
<TabItem Header="tab 2">
<ListBox>
<ListBoxItem>
<TextBlock Text="item 2-1"/>
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="item 2-2"/>
</ListBoxItem>
</ListBox>
</TabItem>
</TabControl>
Update: I set IsSynchronizedWithCurrentItem="True" on the listbox and all seems to be well.
Based on your comment I would guess something is changing in your viewmodel to remove the selected item. Can you set a breakpoint on the setter of SelectedDevice and check the call stack?
To test that can you remove the SelectedItem={} code and see if it stays selected when you change tabs?
To answer more completely I would need to see more code.
Related
I have a list view that will contain notes that I input. I am having trouble figuring out how to have the list view item look how I want it to.
Below is how it should look:
And this is what it currently looks like:
How do I write the list view item in XAML so that the Date and time appear to the very top-right of each list view item, with the text of the note to the left?
<ListView x:Name="list" ItemsSource="{Binding Note}" BorderBrush="{x:Null}" BorderThickness="0">
<DataTemplate>
<ListViewItem>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ListViewItem>
</DataTemplate>
</ListView>
Any help at all is much appreciated!
You are missing a number of elements required in order to get your screen to look the way you want.
You need to define the ItemTemplate for the ListView. You're on the right track here, it is a DataTemplate declared in XAML, you just have to apply it to the ListView.ItemTemplate property.
You need to set the HorizontalContentAlignment of the ListView to Stretch (the default is Left, which means your items will not fill the entire content area).
You need to use a DockPanel (or other similar panel) inside your DataTemplate to place your date content on the right, and the remainder of your content on the left.
You need to disable Horizontal Scrolling (ScrollViewer.HorizontalScrollBarVisbility) on the ListView in order to make your content wrap (otherwise it will just happily draw it all on one line).
I've included a sample ListView that should get you started.
<ListView
ItemsSource="{Binding Items}"
HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock
TextWrapping="Wrap"
Text="{Binding Date}"
Background="Magenta"
DockPanel.Dock="Right" />
<TextBlock Text="{Binding Content}" Background="Lime" />
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I try to create a listbox in my Windows Phone app. I tried to create a custom datatemplate for it. In a lot of sample I saw similar to this simple listbox:
<ListBox Width="350">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Test text 1" />
<TextBlock Text="Test text 2" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is very simple isn't it? However the UI shows nothing. I can put textblocks and other control on the grid. I also tried using binding and itemssource but still nothing.
If I'm not using datatemplate just a simple textblock it shows the textblock:
<ListBox Width="350">
<TextBlock Text="haha" />
</ListBox>
Does anyone have any idea what do I wrong?
Thanks!
I think you need to bind the ItemSource of the listbox to something with items in it.
The second sample shows up because you are setting the content of the listbox directly.
I'm interesting, can I group some controls (image, 2-3 textboxes) in one element, and then push group of this elements in listbox? I'm trying to make a news reader of russian social network Vkontakte into Windwos Phone 7.
Each news has an image, text, and some other metadata. So I want to group all this info in one control and use it in listbox.
I tryied to push a grid(which had an image and two textboxes) into listbox, but it throws XamlParseException.
Also, I need to get the content of theese textboxes and images from code. In grid I can use
<Grid.Resources>
<src:Customers x:Key="customers"/>
</Grid.Resources>
Here is what you need:
A collection (ObservableCollection<T> recommended) of models (News in you case).
A ListBox
A DataTemplate
Example:
XAML:
<ListBox Name="ListBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
...
<Image Source="{Binding ImagePropertyInModel}" ... />
<TextBlock Text="{Binding TextPropertyInModel}" ... />
...
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind:
ListBox1.ItemsSource = <collection of models>;
Instead of the <Grid> in <DataTemplate> you can use a Custom Control (Templated Control) or a User Control that you may already have.
You can create an UserControl with the controls you want to use. With your ListBox you do something like:
<ListBox ItemsSource="{Binding Path=YourItemsSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<my:MyUserControl DataContext="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As ItemsSource of your ListBox you could use a ObservableCollection of News and through DataContext="{Binding}" you can bind to the News properties in your UserControl, e.g.:
<UserControl...>
<Image Source="{Binding Path=photoAttachment}"/>
</UserControl>
Right now I use a ListBox but that allows the user to select an item which I don't want. Is there a way to disable selecting or a more suitable control I can use?
Right now I have this:
<ListBox ItemsSource="{Binding Path=PersonNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontSize="20"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Use an ItemsControl, it's a base class without selection. (As it does not provide its own ScrollViewer you may need to add one (either in the template or around the control) if you need scrolling)
See the ListView control.
I do not know what the container/control im looking for would be called, so I cannot really search for it.
Add More of Same Usercontrol Usercontrol
Clicking on + would add a new instance of My Usercontrol to the right of the existing ones
Clicking on X would dispose the usercontrol that was clicked
I'm not really looking for a tab control that would put each new instance on a new tab, but if there is nothing else then it might do.
The design is not to be as shown in the image obviously, the image just illustrates the basic idea
Any keyword/name suggestions or links to existing implementations?
e.g. Maybe there is a style that turns a ListBox into something suitable?
I would use an ItemsControl and customize it's ItemsPanelTemplate to be whatever you want.
ItemsControls are meant for iterating through a collection of objects, and displaying them in whatever form you want. I wrote some simple code samples of them here if you're interested, or here's another quick example:
<DockPanel x:Name="RootPanel">
<Button Style="{StaticResource AddButtonStyle}"
DockPanel.Dock="Right" VerticalAlignment="Center"
Command="{Binding AddItemCommand" />
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<local:MyUserControl />
<Button Style="{StaticResource RemoveButtonStyle}"
Command="{Binding ElementName=RootPanel, Path=DataContext.RemoveItemCommand}"
CommandParameter="{Binding }"
HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
Your ItemsControl would be bound to an ObservableCollection of objects, and your Add/Remove buttons would simply add/remove items from that collection. Since it is an ObservableCollection, it will notify the UI when the collection gets changed and automatically update.
You can indeed use a ListBox and set its ItemTemplate and ItemsPanelTemplate:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Of course, your ItemTemplate would be a reference to your control.
You could look at something called a carousel control which uses a list of objects behind it and displays them similarly to itunes. This could be a bit over the top but is one solution. An example can be seen here
If this is too advanced for your needs, could it be as simple as a stackpanel with a scrollbar which is bound to a list of your user controls?