0

I'm building a plugin system and I want it to be as dynamic as possible - and such, I want a settings panel for it too. For this, I'd create the settings page from a Dictionary, where TKey defines the label of the parameter, and TValue defines the type of the parameter. However I'm yet to find an easy way to generate the actual UI. I don't want to do much, it would be a simple StackPanel, with a pre-defined TextBlock-TextBox pair - and each of these would represent one of the Dictionary entries.

How could this be done in an easy way?

fonix232
  • 2,132
  • 6
  • 39
  • 69

1 Answers1

0

A Dictionary is not optimal for binding, since the KeyValuePair it returns is immutable (and hence can not be used in a two-way binding).

If you still want to keep the data in a dictionary, you could wrap it in a class that contains the key (to have something to display in the TextBlock). One way of doing it:

// some classes to represent our settings
public abstract class Parameter
{
    public string Key { get; private set; }
    public Parameter( string key ) { this.Key = key; }
}

public class StringParameter : Parameter
{
    public string Value { get; set; }
    public StringParameter( string key, string value ) : base( key )
    {
        this.Value = value;
    }
}

Some test data:

public Dictionary<string, Parameter> m_Settings = new Dictionary<string, Parameter>();
// NOTE: we're returning the dictionary values here only
public IEnumerable<Parameter> Settings { get { return m_Settings.Values; } }

...

var p1 = new StringParameter( "Parameter 1", "Value 1" );
var p2 = new StringParameter( "Parameter 2", "Value 2" );
var p3 = new StringParameter( "Parameter 3", "Value 3" );

m_Settings.Add( p1.Key, p1 );
m_Settings.Add( p2.Key, p2 );
m_Settings.Add( p3.Key, p3 );

And a very simple UI:

<Window ...
        xmlns:self="clr-namespace:WpfApplication8"
        DataContext="{Binding RelativeSource={RelativeSource Self}}" >
    <ItemsControl ItemsSource="{Binding Settings}">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type self:StringParameter}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Key}"/>
                    <TextBox Text="{Binding Value, Mode=TwoWay}"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>            
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Window>

Having a generic base Parameter allows you to have different types of settings, all with their own DataTemplate. Note that all this lacks any validation and all that stuff you'll need as well.

Chris
  • 5,442
  • 17
  • 30
  • As you might have seen from my sample, I do not intend to save the settings into the Dictionary itself, I'm merely using it for the description of the fields (name and type). The actual settings will be stored separately. – fonix232 May 03 '15 at 10:29
  • I see. Well, then just skip the dictionary and bind to a list of classes describing the settings (as I've done). Then when the user is done, just grab the values from the list. You could obviously generate the UI old school, but since you're in WPF binding is the way to go. – Chris May 03 '15 at 13:15