Окно WPF для редактирования пользовательских настроек. Почему значения не меняются? - PullRequest
1 голос
/ 18 февраля 2020

Я работаю над окном wpf для редактирования пользовательских настроек.

Это то, что я сделал до сих пор:

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

Значения отображаются, но они не обновляются в Properties.Settings.Default, когда я изменяю и сохраняю их с помощью Properties.Settings.Default.Save();. Является ли двустороннее связывание правильным?

Спасибо

1 Ответ

1 голос
/ 18 февраля 2020

Как предлагается в комментариях и в этом ответе , мне нужно инкапсулировать System.Configuration.SettingsPropertyValue в ViewModel, которая реализует INotifyPropertyChanged. В противном случае привязка не будет работать.

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;
}

Новое свойство для привязки:

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

Правильный просмотр и правильные шаблоны данных:

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