简体   繁体   中英

Handling styling with data binding

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 (ie 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, ie

<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:

  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 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM