REWRITTEN
I have an application that receives a file. This file has a large amount of editable content. This content comes in a variety of possible types (i.e. boolean checkboxes, textboxes, etc). The issue is, these values can be either alone, or in a group (up to 8), so they come in arrays. We bind these values to a ListView
, and use DataTemplates
to display them. Effectively, I create the ListView
from a list of arrays.
The items in these arrays need to be data bound and styled properly (for example, a boolean array needs to create checkboxes, while a string array needs textboxes). Each created element needs to be put into a column in the ListView
. The current styling is using DataTemplates
with data binding, i.e.
<DataTemplate x:Key="testTemplate2">
<TextBlock Text="{Binding Path=Value[0]}"
Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
This is repeated for every value in the input array, so you have Value[1]
, Value[2]
, etc.
This means repeating almost the same code 8 times, and then doing the same for the next type. Since there is a large amount of input types, this means a ridiculous amount of repeated code.
My question is: Is there a better way to do this, so we don't have to repeat data templates, while keep using columns?
By the way, I am using .NET 3.5.
Example of how a row would look like. Each element would be in its own column. The comboboxes are built from the array.
EDIT Example DataTemplate:
<DataTemplate x:Key="textBoxTemplate2">
<TextBox Text="{Binding Path=Value[2], NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="{DynamicResource ComboBorder}"
Tag="{Binding Path=AllowedChars}"
PreviewTextInput="PreviewTextInputHandler"
DataObject.Pasting="PastingHandler"
ToolTip="{Binding Path=Title}"
Margin="2"
SourceUpdated="BindingSourceUpdated"
MaxLength="{Binding Path=DataLength}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" >
<TextBox.IsEnabled>
<MultiBinding Converter="{StaticResource isEnabledConverter}">
<Binding Path="IsLocked" Mode="OneWay" />
<Binding Path="IsVisible[2]" Mode="OneWay" />
</MultiBinding>
</TextBox.IsEnabled>
</TextBox>
</DataTemplate>
Example diagram:
I have a ViewModel. This ViewModel has a List, made of ItemData. Class ItemData has an array called Values. The List is bound to the View. We need to choose what DataTemplate to use depending on what property of ItemData we're accessing:
Currently, we display the List in a ListView. When generating the ListView
, the columns have different DataTemplates
attached to their CellTemplate
s, one per index, for a total of 8 DataTemplates.
My Answer is focused on your words : Since there is a large amount of input types, this means a ridiculous amount of repeated code.
Code Reuse:
Since you in your Item template
needs to define different kind of controls for different DataTypes
, so that code can't be reduced completely. I mean if you want TextBox
for String
type or Checkbox
for Bool
type that code can't be reduced obviously. However what you can reduce is defining Binding
syntax again and again for different template
as I can see in your TextBox
Template
example. You can define the Biniding
once and then reused them again and again with n number(8 in your case) of controls. Below is how you do it:
public class BindingResourceExtension : StaticResourceExtension
{
public BindingResourceExtension() : base() { }
public BindingResourceExtension(object resourceKey) : base(resourceKey) { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = base.ProvideValue(serviceProvider) as BindingBase;
if (binding != null)
return binding.ProvideValue(serviceProvider);
else
return null; //or throw an exception
}
}
XAML
<Window.Resources>
<ResourceDictionary>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</ResourceDictionary>
</Window.Resources>
(...)
<TextBox Text="{ns:BindingResource MyBinding}" />
<CheckBox IsChecked="{ns:BindingResource MyBinding}" />
So some reuse of code can be achieved( Imaging above code with large and complex bindings
). After you posted your question I was searching for something like this so I posted another question for binding reuse and it helped. Also as Bindings
will be centralize they will be easy to update.
ItemTemplate:
Apart from your code reuse problem you can use nested ItemsControl
as by looking your class digram I can see and also suggested in another answer:
<ListBox ItemsSource="{Binding CollectionOfArrays}">
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Array}" />
</DataTemplate>
</ListBox.ItemTemplate>
Now for inner ItemsControl
you have to actually define the Templates
, but I think you are already clear on that part.