Michele mpp Marostica
Michele mpp Marostica

Reputation: 2472

WPF Window to edit the user.settings. Why values are not changing?

I'm working on a wpf window to edit the user settings.

This is what I did so far:

<ListView Grid.Row="1"
        ItemsSource="{Binding Source={x:Static properties:Settings.Default}, Path=PropertyValues}"
        HorizontalContentAlignment="Stretch" Background="LightGray"
        ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListView.ItemTemplate>
        <DataTemplate>
            <DockPanel HorizontalAlignment="Stretch"
                    IsEnabled="{Binding DataContext.Enabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">

                <Label Width="200" Content="{Binding Name}"/>
                <Label Width="200" Content="{Binding Path=Property.PropertyType}" Foreground="Gray" FontStyle="Italic"/>
                <ContentControl VerticalContentAlignment="Center" Content="{Binding Path=PropertyValue}">
                    <ContentControl.Resources>
                        <ResourceDictionary>
                            <DataTemplate DataType="{x:Type sys:Boolean}">
                                <CheckBox IsChecked="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </DataTemplate>
                            <DataTemplate DataType="{x:Type sys:String}">
                                <TextBox Text="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </DataTemplate>
                            <DataTemplate DataType="{x:Type sys:Int32}">
                                <TextBox Text="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </DataTemplate>
                        </ResourceDictionary>
                    </ContentControl.Resources>
                </ContentControl>
            </DockPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

The values are showing but they're not updated in Properties.Settings.Default when I change and save them with Properties.Settings.Default.Save();. Is the two way binding correct?

Thanks

Upvotes: 1

Views: 56

Answers (1)

Michele mpp Marostica
Michele mpp Marostica

Reputation: 2472

As suggested in the comments and in this answer, I need to encapsulate the System.Configuration.SettingsPropertyValue into a ViewModel that implements INotifyPropertyChanged. Otherwise the binding won't work.

ViewModel:

public class SettingsPropertyValueProxy : INotifyPropertyChanged
{
    public string Name { get; }
    public Type PropertyType => PropertyValue.GetType();
    public object PropertyValue
    {
        get
        {
            return Properties.Settings.Default[Name];
        }
        set
        {
            try
            {
                Properties.Settings.Default[Name] = Convert.ChangeType(value, PropertyType);
                Properties.Settings.Default.Save();
            }
            catch
            { }
        }
    }

    public SettingsPropertyValueProxy(string name)
    {
        Name = name;
        Properties.Settings.Default.PropertyChanged += (sender, e) => _OnPropertyChanged(e.PropertyName);
    }

    private void _OnPropertyChanged(string propertyName)
    {
        if (propertyName == Name) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PropertyValue)));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

New Property to bind:

public IEnumerable<SettingsPropertyValueProxy> Values { get; } 
    = Properties.Settings.Default.Properties
    .Cast<SettingsProperty>()
    .Select(p => new SettingsPropertyValueProxy(p.Name))
    .OrderBy(p => p.Name)
    .ToArray();

Correct View and Correct DataTemplates:

<ListView Grid.Row="1"
        ItemsSource="{Binding Path=Values}"
        HorizontalContentAlignment="Stretch" Background="LightGray"
        ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListView.ItemTemplate>
        <DataTemplate>
            <DockPanel HorizontalAlignment="Stretch"
                    IsEnabled="{Binding DataContext.Enabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">

                <Label Width="200" Content="{Binding Path=Name}"/>
                <Label Width="200" Content="{Binding Path=PropertyType}" Foreground="Gray" FontStyle="Italic"/>
                <!--<TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay}"/>-->
                <ContentControl VerticalContentAlignment="Center" Content="{Binding Path=PropertyValue}">
                    <ContentControl.Resources>
                        <ResourceDictionary>
                            <DataTemplate DataType="{x:Type sys:Boolean}">
                                <CheckBox IsChecked="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                            DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
                            </DataTemplate>
                            <DataTemplate DataType="{x:Type sys:String}">
                                <TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                            DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
                            </DataTemplate>
                            <DataTemplate DataType="{x:Type sys:Int32}">
                                <TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                            DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
                            </DataTemplate>
                        </ResourceDictionary>
                    </ContentControl.Resources>
                </ContentControl>
            </DockPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Upvotes: 1

Related Questions