MVVM nested list scrolling - c#

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.

Related

WPF Usercontrol, Hosting dynamic content for reuse of UserControl. MVVM

I'll try to be very clear of what I'm trying to accomplish and am open to suggestions on other ways to achieve my desired result.
The 1000 foot view.
I have a UserControl that I want to reuse in every screen in my application. This control is more of a template look and feel with an icon (bindable), dynamic (bindable) label.
UserControl.xaml (CardView.xaml)
<Border BorderBrush="{Binding Path=BorderColor, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<StackPanel Orientation="Vertical" Style="{StaticResource CardStyle}">
<StackPanel>
<Border Style="{StaticResource MyBorderStyle}">
<Label Content="{Binding Path=CardTitle, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</Border>
</StackPanel>
<Label Style="{StaticResource LabelIcon}">
<Path Fill="#FF000000" HorizontalAlignment="Center"
Stretch="UniformToFill" Data="{Binding Path=VectorString, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
// Dynamic Content Here.
// Any kind of XAML content for the consumer of the control.
// not in C# but I want to host the control and put controls in
// here that I can bind to in XMAL by parents view model.
</StackPanel>
</Border>
Consumer code (customer.xaml)
<local:CardView CardTitle="Test" VectorString="F1 M" BorderColor="#FF0088">
// Here's where I want to put dynamic XAML content.
// Want to host anything and bind to it using the consumers View Model.
// Example
<Button Content="{Binding SomeText}" />
<StackPanel>
<Button>..... variable content but bindable
</StackPanel>
</local:CardView>
So in summary I have a user control that I want to to use in multiple places and have variable content in the body. The variable content will be marked up in the consumer XAML.
Some suggestions I've dug up searching, but doesn't seem to fit the model
Use a content template. I was going to but how do you bind to controls in a content template?
Content presenter. How do I bind to consumers view model?
This is pretty easy doable by using a ContentControl. Just insert it into your CardView.xaml:
<Border BorderBrush="{Binding Path=BorderColor, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<StackPanel Orientation="Vertical" Style="{StaticResource CardStyle}">
<StackPanel>
<Border Style="{StaticResource MyBorderStyle}">
<Label Content="{Binding Path=CardTitle, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</Border>
</StackPanel>
<Label Style="{StaticResource LabelIcon}">
<Path Fill="#FF000000" HorizontalAlignment="Center"
Stretch="UniformToFill" Data="{Binding Path=VectorString, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
// Dynamic Content Here.
<ContentControl Content={Binding CustomContent} />
</StackPanel>
And then in your ViewModel add a property 'CustomContent' of type object which contains an instance of your Customer.

Weird issue with WPF TreeView when using mouse wheel to scroll

So, I've been working on a legend for our map using a WPF treeview to display the groups and layers.
I've gotten it working and displaying just fine, but when I scroll the treeview with the mousewheel, the control starts flickering and the vertical scrollbar for the tree keeps resizing up and down.
The treeview layout is like this:
Group
Layer
Layer sub items
Layer
Layer sub items
Layer
Layer sub items
Group
Layer
etc...
The Group and Layer nodes are tree view items, but the layer sub items are contained within an items control. The layer sub items are not meant to be expanded/contracted, or selected and thus must remain static under the layer node, thus the items control seemed like a sensible choice.
When I scroll with the mouse wheel all the way to the top or bottom of the tree view, the scrollbar starts flicking and resizing, the last few elements of the items control flickers in and out of view (when it shouldn't be in view at all), and sometimes, the tree view will actually scroll back and forth.
If I remove the items control, everything works as it's supposed to. And when I add it back in, it messes up.
Also, if I grab the scroller thumb with the mouse and drag it, everything works fine. No jumping around.
Here's the resource XAML for the control:
<views:DynamicLegendNodeTemplateSelector x:Key="LegendTemplateSelector">
<views:DynamicLegendNodeTemplateSelector.GroupTemplate>
<HierarchicalDataTemplate DataType="{x:Type legend:IDynamicMapLegendGroup}">
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding Converter="{StaticResource LegendNode}">
<Binding Path="Groups"/>
<Binding Path="LegendLayers"/>
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<Grid>
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False" IsChecked="{Binding IsVisible}" VerticalAlignment="Center">
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center"/>
</CheckBox>
</StackPanel>
</Grid>
</HierarchicalDataTemplate>
</views:DynamicLegendNodeTemplateSelector.GroupTemplate>
<views:DynamicLegendNodeTemplateSelector.LayerTemplate>
<HierarchicalDataTemplate DataType="{x:Type legend:IDynamicMapLayerLegendItem}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" Focusable="False" IsChecked="{Binding IsVisible}" VerticalAlignment="Center">
<TextBlock Text="{Binding LayerCaption}" VerticalAlignment="Center"/>
</CheckBox>
<ItemsControl Grid.Row="1"
Margin="16,0,0,0"
BorderThickness="0"
Background="Transparent"
ItemsSource="{Binding LegendItems, IsAsync=True}"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
MouseWheel="ItemControls_MouseWheel"
ScrollViewer.CanContentScroll="False"
MouseUp="ItemsControl_MouseUp">
<ItemsControl.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Width="20" Height="20" Stretch="UniformToFill" Source="{Binding Symbol}"/>
<Label Grid.Column="1" Content="{Binding Label}"/>
</Grid>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</HierarchicalDataTemplate>
</views:DynamicLegendNodeTemplateSelector.LayerTemplate>
</views:DynamicLegendNodeTemplateSelector>
<Style x:Key="TreeItemStyle" TargetType="TreeViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<EventSetter Event="MouseUp" Handler="TreeViewItem_MouseUp"></EventSetter>
</Style>
And here's the treeview:
<TreeView x:Name="LegendHierarchy"
MinWidth="200"
ItemsSource="{Binding LegendItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:DynamicArcGisRuntimeMapLegendView}}}"
ItemContainerStyle="{StaticResource TreeItemStyle}"
ItemTemplateSelector="{StaticResource LegendTemplateSelector}" />
This code is using .NET 4.5 in Visual Studio 2015 if that matters.
Regardless, does anyone know what might be causing the problem?
Thanks
So, it goes to show that an attempt at a good nights sleep is helpful.
Apparently, all I had to do was set
VirtualizingPanel.VirtualizationMode="Recycling"
On the treeview control and it starting working.
Here's the full tree view XAML:
<TreeView x:Name="LegendHierarchy"
MinWidth="200"
ItemsSource="{Binding LegendItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:DynamicArcGisRuntimeMapLegendView}}}"
ItemContainerStyle="{StaticResource TreeItemStyle}"
ItemTemplateSelector="{StaticResource LegendTemplateSelector}" UseLayoutRounding="True" ScrollViewer.CanContentScroll="True" HorizontalContentAlignment="Stretch"
VirtualizingPanel.VirtualizationMode="Recycling"/>
I hope this helps others.

Scroll according to selected item in stack panel

I have a view Model that is bind with ItemsControl. Inside that ItemsControl I have a stack panel. Now What I want is that selected item can be changed with arrow keys. Like in the attached picture I have 1st item selected and when I press down 4th item should be selected. The problem is that Items per row depends on screen resolution so On some screen there are 4 items per row and in some there are three. Secondly when I move down to the point where the page ends scroll should move down. How can I achieve this?.
Here is my xaml:
<ScrollViewer HorizontalAlignment="Center" VerticalScrollBarVisibility="Auto" Width="Auto" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Grid.RowSpan="2" VerticalAlignment="Top" Margin="0,10,10,0">
<ItemsControl Name="productVariants">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DockPanel MouseLeftButtonDown="ProductVariantClicked" Tag="{Binding VariantCBX}" Margin="8" MaxHeight="160" MaxWidth="200" MinWidth="200" MinHeight="160">
<Border Name="ItemBorder" CornerRadius="6" BorderBrush="Gray" Background="White" BorderThickness="2" DockPanel.Dock="Top">
<StackPanel Margin="0">
<TextBlock Name="ProductVariantOption" Text="{Binding VariantOption}" HorizontalAlignment="Center" FontWeight="Bold" FontSize="20"/>
<Image Source="{Binding ProductVariantLogoPath}" Height="80" Width="180" />
<TextBlock Text="{Binding VendorName}" HorizontalAlignment="Center" FontSize="15" FontWeight="Bold" />
<TextBlock Text="{Binding SellingPrice}" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold" Foreground="Red" />
</StackPanel>
</Border>
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True" >
<Setter TargetName="ItemBorder" Property="BorderBrush" Value="Yellow"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Like I said, I'm not aware of any clean way to do it. I might start by looking at the ActualWidth of your items (e.g. your "ItemBorder" Border element). If you know the ActualWidth of your item (plus any Horizontal Margin), and the ActualWidth of your ItemsControl, you can figure out how many elements are in one row at that moment. You would need to re-calculate this on-demand -- you could either recalculate this when a scroll is performed (because the sizes may have changed), or you could keep it up-to-date by re-calculating on layout change.
To find the ActualWidths, you have a couple of options. One is you could traverse through the visual descendants at scroll-time until you find the element that you care about. Another is you could subscribe to a"Loaded" event on and remember the actual width at that time, assuming that the widths don't change over time.

Setting bind-values when adding ListviewItems in XAML

I'm sorry if the title is a bit, off. Did not know what to call it really.
But here is my question:
I have a ListView with a custom ItemsTemplate, which has a Textblock and an Image. Both of which are set to get their data from binds.
But here is what I'm wondering:
If I want to add listviewItems from XAML:
<ListView HorizontalAlignment="Left" Width="150" ItemTemplate="{DynamicResource menuItems}" ItemsPanel="{DynamicResource menuLayout}">
<ListViewItem/> <---- Here
<ListViewItem/> <---- And here.
</ListView>
How can I set what values the textblock and image should have?
<ListViewItem "TextBlockValue = asdasdasds"/> etc
Here's the Itemtemplate
<DataTemplate x:Key="menuItems">
<Grid Width="150" Height="35">
<Image Height="35" Width="35" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Path=Text}" Margin="40,0,0,0" VerticalAlignment="Center" FontSize="15" FontWeight="Light" Foreground="White"/>
</Grid>
</DataTemplate>
Simple and most flexible solution
As a first step, a class should be defined which serves as data container for all values of one ListViewItem.
public class ItemData
{
public ImageSource ImageSource { get; set; }
public string Text { get; set; }
}
(Technically, one could also do it also without such a custom class; however, the resulting XAML will look much more convoluted and much less readable.)
The data template with the bindings to the properties of ItemData elements could look like this:
<DataTemplate x:Key="menuItems">
<StackPanel Width="150" Height="35" Orientation="Horizontal">
<Image Source="{Binding Path=ImageSource}" Height="35" Width="35" />
<TextBlock Text="{Binding Path=Text}" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="15" FontWeight="Light" Foreground="White"/>
</StackPanel>
</DataTemplate>
In the XAML of the ListView, a collection of ItemData objects will be constructed and assigned to the ListView.Items property. The ListView will create the ListViewItems accordingly.
<ListView HorizontalAlignment="Left" Width="150" ItemsPanel="{DynamicResource menuLayout}" ItemTemplate="{StaticResource menuItems}">
<ListView.Items>
<My:ItemData ImageSource="x:\\path\\to\\Img_1.png" Text="Alpha" />
<My:ItemData ImageSource="x:\\path\\to\\Img_2.png" Text="Beta" />
</ListView.Items>
</ListView>
Solution with explicit ListViewItem declarations
The question sounds like a solution with explicit declarations of ListViewItems is sought.
However, this should not really be the recommended approach, as it will only lead to more convoluted XAML for achieving exactly the same result as the first solution, as demonstrated now.
In the XAML of the ListView, each ListViewItem together with the appropriate ItemData object will be constructed, and also the data template will be assigned to ListViewItem.ContentTemplate (ListView.ItemTemplate won't work here, since the ListViewItems are not created by the ListView).
<ListView HorizontalAlignment="Left" Width="150" ItemsPanel="{DynamicResource menuLayout}">
<ListViewItem ContentTemplate="{StaticResource menuItems}">
<ListViewItem.Content>
<My:ItemData ImageSource="x:\\path\\to\\Img_1.png" Text="Alpha" />
</ListViewItem.Content>
</ListViewItem>
<ListViewItem ContentTemplate="{StaticResource menuItems}">
<ListViewItem.Content>
<My:ItemData ImageSource="x:\\path\\to\\Img_2.png" Text="Beta" />
</ListViewItem.Content>
</ListViewItem>
</ListView>
If specifying the ContentTemplate for each single ListViewItem is not desired, a ListViewItem Style setting the ListViewItem.ContentTemplate property can be defined in the ListView's resource dictionary:
<ListView HorizontalAlignment="Left" Width="150" ItemsPanel="{DynamicResource menuLayout}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContentTemplate" Value="{StaticResource menuItems}" />
</Style>
</ListView.Resources>
<ListViewItem>
<ListViewItem.Content>
<My:ItemData ImageSource="x:\\path\\to\\Img_1.png" Text="Alpha" />
</ListViewItem.Content>
</ListViewItem>
<ListViewItem>
<ListViewItem.Content>
<My:ItemData ImageSource="x:\\path\\to\\Img_2.png" Text="Beta" />
</ListViewItem.Content>
</ListViewItem>
</ListView>
The style being defined inside the ListView's resource dictionary prevents any other ListViewItem control outside of this ListView from accidentally picking up this style.
Comparing the simplicity of the first solution with the verbosity of the second, it is obvious that explicit declarations of ListViewItems in XAML is not a recommended approach.

Userdefinable Layout (at runtime)

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.

Categories

Resources