I'm looking for a best practise in the following scenario. This scenario has been made up just to illustrate the problem in a simplified manner.
Assuming we have the following Layout, to store an address.
Though some customers might think, the e-mail is more important than the name, and hence would like to display it before the name. Some customers might need more space for the name. Some customers cry because they don't need any phone numbers at all.
My goal: The user should be able to decide, how his form looks like.
I would like to set up a default template which should work for most customers.
I prefer not to reinvent the wheel, so is there any library which provides such functionality?
Such functionality could be (at runtime):
Reorder Controls (e.g. with drag and drop)
Store and Load UI Layout Templates
Set Controls Visible / Invisible
Resize Controls
If not, what would be the "best practise" to solve this?
If I had to reinvent the wheel, the most probable solution would be to create my own XML, which I would load at runtime and then set the rows and columns.
But since I'm quite new to WPF, I don't know if this was a proper solution.
At last, below is the XAML of the above example:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Name:"/>
<Label Grid.Row="1" Grid.Column="0" Content="E-Mail:"/>
<Label Grid.Row="2" Grid.Column="0" Content="Phone:"/>
<Label Grid.Row="3" Grid.Column="0" Content="Address:"/>
<TextBox Grid.Column="1" Grid.Row="0" Margin="3" />
<TextBox Grid.Column="1" Grid.Row="1" Margin="3" />
<TextBox Grid.Column="1" Grid.Row="2" Margin="3" />
<TextBox Grid.Column="1" Grid.Row="3" Margin="3" />
<Button Grid.Column="1" Grid.Row="4" HorizontalAlignment="Right" MinWidth="80" Margin="3" Content="OK" Click="Button_Click" />
</Grid>
Firstly, it is good that you ask this question before creating the application. Secondly, I think to this task dynamically creating View perfect come up DataTemplate. You should begin right away to develop your application in MVVM style, it would be more appropriate for dynamic View.
In the DataTemplate, the key role played DataTrigger. They allow depending on the value set property for an element that is in View. For example, the show / hide button, set the Height / Width, etc.
Example of DataTemplate:
<DataTemplate x:Key="MainView" DataType="{x:Type ViewModels:MainViewModel}">
<Grid>
<Button Name="UserButton"
Content="Are you user?"
Width="100"
Height="30"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding UserButtonCommand}" />
<Button Name="AdminButton"
Content="Are you admin?"
Width="100"
Height="30"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Command="{Binding AdminButtonCommand}" />
<StackPanel Name="MainViewPanel"
Tag="{Binding Path=MainModel.ContentType,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}">
<TextBlock Name="TitleTextBlock"
Text="{Binding Path=MainModel.TitleText,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
FontSize="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="Collapsed" />
<TextBox Name="BannedTextBlock"
Text="{Binding Path=MainModel.BannedName,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Visibility="Collapsed" />
<Button Name="YesButton"
Content="{Binding Path=MainModel.ContentYesButton,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Visibility="Collapsed" />
<Button Name="NoButton"
Content="{Binding Path=MainModel.ContentNoButton,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Visibility="Collapsed" />
</StackPanel>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=MainViewPanel, Path=Tag}" Value="User">
<Setter TargetName="TitleTextBlock" Property="Visibility" Value="Visible" />
<Setter TargetName="YesButton" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MainViewPanel, Path=Tag}" Value="Admin">
<Setter TargetName="TitleTextBlock" Property="Visibility" Value="Visible" />
<Setter TargetName="BannedTextBlock" Property="Visibility" Value="Visible" />
<Setter TargetName="YesButton" Property="Visibility" Value="Visible" />
<Setter TargetName="NoButton" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Given two buttons, one for the user and one for the administrator. If you choose the User, the content is displayed to the user, if the Admin, then for administrator. Content type specified in the Tag of StackPanel. Pay attention to the section <DataTemplate.Triggers>.
Complete example and description of an example is here (he still quite large):
Make (create) reusable dynamic Views
For the reordering part, you can combine Anatoliy Nikolaev's answer with a listbox and Gong Drag and Drop reorder => https://github.com/punker76/gong-wpf-dragdrop
The default layout of the listbox can easily be changed so that you don't have the selected items highlighting and so on.
You might also consider to provide two dynamic views, one for the actual form and one to edit the said form. Also at some point you will have to save the configuration for each user.
Related
Can you suggest a good way to make a switch between horizontal and vertical split in wpf? I have two areas in my interface. Want them to be divided by a draggable separator and to have a button to switch between horisontal and vertical split. I tried to do that with AvalonDock, but for some reason that didn't work. Here's my question on it, nobody answered yet. prev. question
Maybe another library, or a simple way of doing that with standard GridSplitter?
I just ran into a similar problem. Here is how I solved it, thanks to some good ideas here:
<ContentControl>
<ContentControl.Resources>
<BoolConverter x:Key="BoolToLayoutConverter" TrueValue="templateHorizontal" FalseValue="templateVertical"/>
<BoolConverter x:Key="BoolToLayoutCharacterConverter" TrueValue="—" FalseValue="|"/>
<DataTemplate x:Key="mainTable">
<StackPanel>
<Label Content="MainTable goes here"/>
<ToggleButton Content="{Binding LayoutHorizontal, Converter={StaticResource BoolToLayoutCharacterConverter}}"
IsChecked="{Binding LayoutHorizontal}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="childTables">
<Label Content="ChildTables go here"/>
</DataTemplate>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding LayoutHorizontal}" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="10"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" ContentTemplate="{StaticResource mainTable}"/>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<ContentPresenter Grid.Column="2" ContentTemplate="{StaticResource childTables}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding LayoutHorizontal}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="5"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" ContentTemplate="{StaticResource mainTable}"/>
<GridSplitter Grid.Row="1" Height="10" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<ContentPresenter Grid.Row="2" ContentTemplate="{StaticResource childTables}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Where BoolConverter is an IValueConverter. And the code behind:
private bool _layoutHorizontal = true;
public bool LayoutHorizontal
{
get { return _layoutHorizontal; }
set
{
_layoutHorizontal = value;
NotifyPropertyChanged();
}
}
I don't know of any reasonably clean way to redefine grid rows and columns of a grid at runtime. You would need some code that redefines the RowDefinitions and ColumnDefinitions, as well as possibly updating Grid.Row and Grid.Column attached properties of the children of the grid. I am not sure how well a grid responds to such a reconfiguration. You might need to invalidate some things manually. I suspect the library you tried to use did not implement all of the steps necessary to reconfigure the grid, or perhaps they tried and found that it did not work.
However, it should be relatively straightforward to swap out one preconfigured grid for another. Put both grids in the same place and set the visibility of the one not currently in use to collapsed.
I am trying to show one collapsed stackpanel on button click, but I'm having problems so I tried reverse my thoughts and I was able to collapse an visible stackpanel. But unfortunately I was unable to implement the behavior I want, show an collapsed stack panel on button click. To the code :D
XAML
<Button x:Name="sentButton" Content="Add Friend" Style="{DynamicResource FlatButtonStyle}" Margin="493,0,0,0" HorizontalAlignment="Left" Width="106"/>
<StackPanel Style="{DynamicResource stackCollapsed}" Visibility="Collapsed">
<Label Content="Invite Friends" FontWeight="Bold" Margin="0,0,477,0" Height="32" />
<StackPanel Orientation="Horizontal" Margin="26,0,0,0">
<Label Content="Enter your friend's email" Width="222" Height="25" />
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource MyTextBox}" x:Name="textBoxEmail" Width="298"/>
<Button x:Name="button1" Content="Send" Command="{Binding AddCommand}" Width="77" Style="{DynamicResource FlatButtonStyle}" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
Styles
<!-- Style Collapsed-->
<Style x:Key="stackCollapsed" TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=sentButton,Path=IsPressed}" Value="true">
<Setter Property="StackPanel.Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
Instead of Button use ToggleButton and bind StackPanel.Visibility to ToggleButton.IsChecked property via BooleanToVisibilityConverter converter
<ToggleButton x:Name="sentButton" Content="Add Friend" Margin="493,0,0,0" HorizontalAlignment="Left" Width="106"/>
<StackPanel Visibility="{Binding ElementName=sentButton, Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}">
<Label Content="Invite Friends" FontWeight="Bold" Margin="0,0,477,0" Height="32" />
<StackPanel Orientation="Horizontal" Margin="26,0,0,0">
<Label Content="Enter your friend's email" Width="222" Height="25" />
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" x:Name="textBoxEmail" Width="298"/>
<Button x:Name="button1" Content="Send" Command="{Binding AddCommand}" Width="77" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
where converter is defined as below
<Window.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</Window.Resources>
The problem is the Visibility property in the <StackPanel> tab takes a higher precedence than anything set in a Style or Trigger, so the Trigger never gets applied. See the Dependency Property Precedence List for more details.
To fix your current solution, move the Visibliity property out of the <StackPanel> tag and into your Style, like this :
<Style x:Key="stackCollapsed" TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=sentButton,Path=IsPressed}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<StackPanel Style="{DynamicResource stackCollapsed}">
...
</StackPanel>
That said, I would personally recommend something like a Toggle Button with the StackPanel.Visibility bound to the ToggleButton.IsChecked, like this answer suggests.
I solved set the Children to null
stackPanel.Children.Clear();
this work if you need to show / hide the panel the first time, it doesn't work if you need to do runtime
Simple as Stackpanel.Visibility = Visibility.Collapsed.
I made a Usercontrol with a Combobox with itemTemplate. I set a an event trigger for click on Item. but its not work completely. it dosent accept the click. around the template or empty place before my text.
this is my code
<Combobox>
<Combobox.ItemTemplate>
<DataTemplate>
<Grid Height="25" FlowDirection="RightToLeft">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition MinWidth="100" />
<ColumnDefinition Width="25" />
</Grid.ColumnDefinitions>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<command:EventToCommand Command="{Binding Command}"
CommandParameter="{Binding CommandParameter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Image Height="20" Width="25" Grid.Column="0" VerticalAlignment="Center"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding Title}" Grid.Column="1" VerticalAlignment="Center" />
<TextBlock Grid.Column="2" />
</Grid>
</DataTemplate>
</Combobox.ItemTemplate>
</Combobox>
it is a usercontrol that binds to a list of object contains Command and commandparameter, on click on each item one command should be raised.
Visual elements need to be assigned a brush in order for hit testing to take place.
(I did say IsHitTestVisibile so you wouldn't confuse the two).
You can do the following above your ItemTemplate in the Container that hosts it like so :
<ComboBox>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}"> <!-- Or based on any other ComboboxItem style you have-->
<Setter Property="Background" Value="Transparent" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
FYI : IsHitTestVisibile is a flag stating that even if a Hit test did pass you can choose to disregard it.
What's wrong with SelectionChanged event of ListBox?
You could bind to that.
DataTemplate is for the data not for UI events. You use data-templates to tell WPF how you want to display data. At most you could have DataTriggers (which is again belong to data).
If you want to trap the click event on items, use ItemContainerStyle. The ItemContainerStyle is for styling the container of dataitem, which is ListBoxItem in this case.
Something of this sort might help:
<Style TargetType="ListBoxItem">
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
</EventTrigger>
</Style.Triggers>
</Style>
I need to fix a list with elements that have different types. Each of the type has it's own datatype to represent the viewmodel for each type. The following code works for me, but for some reason the data inside gets truncated, to some value (looks like default). I need to remove this trancation.
Here is what I have. This code is in the control, that could be placed in a list as well (it could be doubled or tripled). But I Don't think it's relevant.
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ListView DockPanel.Dock="Top" Name="testCaseResultListView"
ItemsSource="{Binding LogItems}"
ItemContainerStyleSelector="{StaticResource fixSideViewLogItemStyleSelector}"
SelectionMode="Single"
>
<ListView.View>
<GridView x:Name="gridView2">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn CellTemplateSelector="{StaticResource fixSideViewLogItemTemplateSelector}"/>
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
</DockPanel>
fixSideViewLogItemTemplateSelector and fixSideViewLogItemStyleSelector are the selectors, that return different datatypes or styles for each of the type in LogItems. The common datatype is a grid with two columns, but that also seems irrelevent - I tried to put a textbox there, and it still gets truncated.
I would like this column to be stretched to the whole gridView. When I set width, of the column, I see the column resizing, but I want it to occupy the whole space. This should be elastic - if I put one control in the window, it should occupy the whole window, and properly resize (with it's column) when the window is resized. If I put two controls, they should divide the space by halves, and still should be resized when the window is resized.
Any help, tips?
Upd
Here is an example of the template I'm using.
<DataTemplate x:Key="testCaseDataResultTemplate">
<!-- Test case results -->
<Grid Margin="50,0,0,0" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<!--Test case result property-->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<!--Is retry / Name-->
<RowDefinition />
<!--Test case number-->
<RowDefinition />
<!--Low limit-->
<RowDefinition />
<!--High limit-->
<RowDefinition />
<!--Measured-->
<RowDefinition />
<!--State-->
<RowDefinition />
<!--Test time-->
<RowDefinition />
<!--Comment-->
</Grid.RowDefinitions>
<!--Is retry / Name-->
<Image Grid.Column="0" Grid.Row="0"
Source="..\Resources\retry16.png"
Stretch="None" HorizontalAlignment="Left"
Visibility="{Binding Path=IsRetry, Converter={StaticResource boolToVisibilityConverter}}" />
<TextBlock Text="fh fhgfhg fhfhfhgfhg fhgfhfhgfhgfhgfhgfhgfhgf hgfhgfhgfhgfhgfhg fhfhgfhgf hgfhgfhfhg fhfhgf rdederserswerv 2" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" TextWrapping="Wrap" MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}"/>
<!--Test case number-->
<TextBlock Text="Number:" Grid.Column="0" Grid.Row="1" />
<TextBlock Text="{Binding Path=TestCaseNumber}" Grid.Column="1" Grid.Row="1" />
<!--Low limit-->
<TextBlock Text="Low limit:" Grid.Column="0" Grid.Row="2" />
<TextBlock Text="{Binding Path=TestCaseData.LimitData.LowLimit}" Grid.Column="1" Grid.Row="2" />
<!--High limit-->
<TextBlock Text="High limit: " Grid.Column="0" Grid.Row="3" />
<TextBlock Text="{Binding Path=TestCaseData.LimitData.HighLimit}" Grid.Column="1" Grid.Row="3" />
<!--Measured-->
<TextBlock Text="Measured" Grid.Column="0" Grid.Row="4" />
<TextBlock Text="{Binding Path=MeasuredValue, Converter={StaticResource valasaConverter}}" Grid.Column="1" Grid.Row="4" />
<!--State-->
<TextBlock Text="Passed: " Grid.Column="0" Grid.Row="5" />
<TextBlock Text="{Binding Path=Passed}" Grid.Column="1" Grid.Row="5" />
<!--Test time-->
<TextBlock Text="Test time: " Grid.Column="0" Grid.Row="6" />
<TextBlock Text="{Binding Path=TestTime, StringFormat={}{0:hh':'mm':'ss'.'ff}}" Grid.Column="1" Grid.Row="6" />
<!--Comment-->
<TextBlock Text="{Binding Path=ShortMessage}"
Grid.Column="0" Grid.Row="7" Grid.ColumnSpan="2"
Visibility="{Binding Path=HasComment, Converter={StaticResource boolToVisibilityColConverter}}"
VerticalAlignment="Stretch"
MaxWidth="400"
TextAlignment="Center">
<TextBlock.ToolTip>
<StackPanel>
<TextBlock Text="{Binding Path=FullMessage}"/>
</StackPanel>
</TextBlock.ToolTip>
</TextBlock>
</Grid>
</DataTemplate>
It's a bit messy, but it is very simple. It has two columns - the captions, and the values. These columns are nothing to do with truncation.
I have tried also this template:
<DataTemplate x:Key="testCaseDataResultTemplate">
<TextBlock Text="Long long text goes here...... ->" HorizontalAlignment="Stretch"/>
</DataTemplate>
The text was of course longer :) It was still truncating, so I blame the listView/GridView, but not the inner template.
I think that this issue maybe is that you need to set the ListView.HorizontalContentAlignment to Stretch. Also the item container style and the item template must have the HorizontalAlignment to Stretch and the Width property must be Auto. Hope this tips helps...
EDIT
Also I think the problem could be the width of the GridViewColumn, that fix the items width
to it's own width. If you are using a single column, maybe you can change the ListView to a ListBox or an ItemsControl, just an idea.
I don't know what your templates looks like but I see a problem like this, it normally lies with a TextBlock that isn't wrapping and/or that the TextBlock's width is longer than it's parent.
Cannot say that I solved the puzzle, but at least it works as I expected. I removed the whole definition with GridView and columns inside, and put ItemTemplateSelector directly in ListView.
So my ListView looks now like this:
<ListView DockPanel.Dock="Top" Name="testCaseResultListView"
ItemsSource="{Binding LogItems}"
ItemContainerStyleSelector="{StaticResource fixSideViewLogItemStyleSelector}"
SelectionMode="Single"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
ItemTemplateSelector="{StaticResource fixSideViewLogItemTemplateSelector}">
That did it! Hope that will help to somebody as well.
I'm currently working on a data driven editing tool that was written in WPF using MVVM. The primary display is a scrollable list of view models, some (not all) of which have inner lists of their own child view models (not scrollable). The problem is that one of the view model types is an array type that includes functionality to add a new child item and we want to make it so that if you use that, it then scrolls the overall list to that new item. Is there a reasonable way to do this using MVVM?
To give you an idea of how this UI is currently set up, this is the overall display:
<Grid ScrollViewer.VerticalScrollBarVisibility="Auto">
<Label Content="{Binding Path=DisplayName}" Height="28" HorizontalAlignment="Left" Margin="4,4,0,0" VerticalAlignment="Top" />
<ItemsControl IsTabStop="False" ItemsSource="{Binding Path=VMEntries}" Margin="12,25,12,12" ItemTemplateSelector="{StaticResource EntryTemplateSelector}" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer x:Name="ScrollViewer">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</Grid>
and this is the data template for the array entry that we're working with:
<DataTemplate x:Key="Array">
<Grid Margin="2,7,0,0">
<Label Content="{Binding Path=DisplayName}" ToolTip="{Binding Path=Tooltip}"/>
<Button Content="Add" HorizontalAlignment="Right" VerticalAlignment="Top" Height="24" Width="24" Command="{Binding Path=AddCommand}"/>
<ItemsControl HorizontalAlignment="Stretch" IsTabStop="False" ItemsSource="{Binding Path=SubEntries, NotifyOnSourceUpdated=True}" Margin="10,24,0,0" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Name="RemoveButton" Grid.Column="0" Margin="0,5,0,0" Content="Del" HorizontalAlignment="Right" VerticalAlignment="Top" Height="24" Width="24" Command="{Binding Path=RemoveCommand}" CommandParameter="{Binding Path=.}"/>
<ContentControl Grid.Column="1" Content="{Binding Path=.}" ContentTemplateSelector="{StaticResource EntryTemplateSelector}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=RemoveHandler}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="RemoveButton" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
The MVVM ideal is not adding code behind, but for some complicated things the easier way is to add it. For several cases if you want add complicated behaviors on your application and keeping the MVVM, an alternative is use the Behaviors (c# codes that allows be used and binds from XAML). Also you could define behaviors using AttachedProperties and register to the PropertyChanged event. And another alternative is to create a UserControl and add the code behind to it.
In your particular case, the inner collection must raise some event when add items to it, and then in your outer collection execute something like this list.ScrollIntoView(itemToScroll);. Hope this could give some tips to go on.