Handling styling with data binding
Asked Answered
S

1

3

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. Example of what I want.

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:

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:

  1. One for the Name
  2. One or more for the Options arrray.

Currently, we display the List in a ListView. When generating the ListView, the columns have different DataTemplates attached to their CellTemplates, one per index, for a total of 8 DataTemplates.

Spermogonium answered 19/4, 2016 at 10:42 Comment(7)
Use an ItemsControl with ItemsSource={Binding Values}?Shakeup
That's what I meant.Shakeup
@Spermogonium can you give the code of some other DataTemplates you have defined, as I want to see how complex they are/could be?Helios
@KyloRen Added an example of one of the DataTemplates. That is probably the second most complex one.Spermogonium
@Spermogonium So foreach item for which you have to display a control on UI, you have collection of some values(cause you have written) Value[2] and visibility collection(IsVisible[2]) etc as data? right? If not can your draw a little diagram of your class structure then it would be very easy to understand and no discrepancy in our understanding.( Cause from template def I'm a little confused that you have written values[2] for next control what will be this value. But I hope it's just a misunderstanding of code and implementation)Helios
@KyloRen Added a diagram with more explanation. But you are right. It is a list of items that are made up of arrays (and other stuff).Spermogonium
@Spermogonium just posted an answer for your code reuse problem with different controls. I think you have got clarity for how values[8] will be converted on UI (by using Itemscontrol in ItemTemplate for each item of listbox and then using your template for inner itemscontrol) by now. So omitting that part from answer.Helios
H
1

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.

Helios answered 3/5, 2016 at 5:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.