为什么我的用户设置仅在第一次调用此方法时保存?

时间:2016-08-09 20:14:04

标签: c# wpf mvvm data-binding settings

我有一个WPF MVVM应用程序,该应用程序从用户设置获取其数据,该用户设置为ObservableCollection类型为Copyable(自定义类),名为Copyables。在主视图模型(ClipboardAssistantViewModel)中,我将CollectionViewSource的来源设置为Copyables。然后将其绑定到主视图中的ItemsControlMainWindow)。此DataTemplate的{​​{1}}是一个用户控件,' CopyableControl',它本质上是一个按钮,但附加属性允许我将数据和命令绑定到它。

当用户点击ItemsControl时,视图模型(CopyableControl)会添加到DefineCopyableViewModel中的ObservableCollection个,并且该集合绑定到ClipboardAssistantViewModel中的ItemsControl。这个MainWindowDataTemplate,名为UserControl,其设置方式使得与点击的DefineCopyableControl相关联的当前值绑定到Copyable中的文本框{1}}进行编辑。

我的问题:DefineCopyableControlDefineCopyableViewModel中有一种方法,该方法仅适用于首次运行(其任务是在进行任何编辑后保存用户设置,并且用户点击< EM>&#34; OK&#34; )。如果我点击EditCopyable()并进行修改,请点击&#34;确定&#34; ,然后再次点击它,再进行一次编辑,然后点击&#34;单击确定&#34; ,然后关闭应用程序并再次打开它,只保存第一个编辑(即使UI已使用编辑的值更新两次)。它似乎与数据绑定有关,需要刷新&#34 ;;请参阅我的调查结果代码中此方法中的注释。

我的代码如下:

型号:

CopyableControl

的ViewModels:

namespace ClipboardAssistant.Models
{
    public class Copyable : INotifyPropertyChanged
    {
        // INotifyPropertyChanged implementation

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if (value != name)
                {
                    name = value;
                    NotifyPropertyChanged("Name");
                }
            }
        }

        private string textToCopy;
        public string TextToCopy
        {
            get { return textToCopy; }
            set
            {
                if (value != textToCopy)
                {
                    textToCopy = value;
                    NotifyPropertyChanged("TextToCopy");
                }
            }
        }

        public Copyable() { }

        public Copyable(string Name, string TextToCopy)
        {
            this.Name = Name;
            this.TextToCopy = TextToCopy;
        }
    }
}

主窗口:

namespace ClipboardAssistant.ViewModels
{
    public class ClipboardAssistantViewModel : INotifyPropertyChanged
    {
        // INotifyPropertyChanged Implementation

        public CollectionViewSource CopyablesView { get; set; }

        public ObservableCollection<DefineCopyableViewModel> Definers { get; set; }

        public CopyableClickCommand CopyableClickCommand { get; set; }

        public ClipboardAssistantViewModel()
        {
            Definers = new ObservableCollection<DefineCopyableViewModel>();

            CopyablesView = new CollectionViewSource();
            CopyablesView.Source = Properties.Settings.Default.Copyables;

            CopyableClickCommand = new CopyableClickCommand(this);
            EditModeClickCommand = new EditModeClickCommand(this);
        }

        public void RefreshCopyables()
        {
            // Both these methods of refreshing appear to have the same effect.
            Properties.Settings.Default.Copyables = (ObservableCollection<Copyable>)CopyablesView.Source;
            CopyablesView.Source = Properties.Settings.Default.Copyables;
        }

        public void EditCopyable(Copyable Copyable)
        {
            Definers.Add(new DefineCopyableViewModel(Copyable, this));
        }
    }
}

namespace ClipboardAssistant.ViewModels
{
    public class DefineCopyableViewModel : INotifyPropertyChanged
    {
        // INotifyPropertyChanged Implementation

        public ClipboardAssistantViewModel MyParent { get; set; }

        public Copyable Copyable { get; set; }

        public DefinerOKClickCommand DefinerOKClickCommand { get; set; }

        public DefineCopyableViewModel(Copyable Copyable, ClipboardAssistantViewModel MyParent)
        {
            this.Copyable = Copyable;
            this.MyParent = MyParent;

            DefinerOKClickCommand = new DefinerOKClickCommand(this);
        }

        public void EditCopyable()
        {
            // Refresh, save, no refresh, save -> doesn't save second edit.

            // Save, refresh, save, no refresh -> does save second edit.

            MessageBoxResult r = MessageBox.Show("Refresh?", "Refresh", MessageBoxButton.YesNo);
            if (r == MessageBoxResult.Yes)
            {
                MyParent.RefreshCopyables();
            }

            // These two MessageBox methods (save and refresh) can be swapped around (see above comments).

            MessageBoxResult s = MessageBox.Show("Save?", "Save", MessageBoxButton.YesNo);
            if (s == MessageBoxResult.Yes)
            {
                Properties.Settings.Default.Save();
            }

            MyParent.Definers.Remove(this);
        }
    }
}

CopyableControl:

<Window x:Class="ClipboardAssistant.Views.MainWindow" x:Name="mainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:vm="clr-namespace:ClipboardAssistant.ViewModels"
                xmlns:ctrls="clr-namespace:ClipboardAssistant.Controls"
                mc:Ignorable="d"
                Title="Clipboard Assistant" Height="400" Width="700">
    <Window.DataContext>
        <vm:ClipboardAssistantViewModel />
    </Window.DataContext>

    <Grid>
        <Grid Margin="15">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="20" />
                <RowDefinition Height="30" />
            </Grid.RowDefinitions>

            <ItemsControl ItemsSource="{Binding CopyablesView.View}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Vertical" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ctrls:CopyableControl Copyable="{Binding}"
                                               ClickCopyable="{Binding DataContext.CopyableClickCommand, ElementName=mainWindow}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <DockPanel Grid.Row="2">
                <Button x:Name="btnEditCopyableMode" HorizontalAlignment="Left" DockPanel.Dock="Left"
                        Content="Edit" Margin="0,0,10,0" Command="{Binding EditModeClickCommand}" />
            </DockPanel>
        </Grid>

        <ItemsControl ItemsSource="{Binding Definers}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>

            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ctrls:DefineCopyableControl Copyable="{Binding DataContext.Copyable}"
                                                 ClickCancel="{Binding DataContext.DefinerCancelClickCommand, ElementName=mainWindow}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>
<UserControl x:Class="ClipboardAssistant.Controls.CopyableControl" x:Name="copyableControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ClipboardAssistant.Controls"
             mc:Ignorable="d" d:DesignHeight="75" d:DesignWidth="200">
    <Grid Width="200" Height="75">
            <Button Command="{Binding ClickCopyable, ElementName=copyableControl}"
                CommandParameter="{Binding Copyable, ElementName=copyableControl}"
                Content="{Binding Copyable.Name, ElementName=copyableControl}"
                Style="{StaticResource CopyableMainButtonStyle}" />
    </Grid>
</UserControl>

DefineCopyableControl:

namespace ClipboardAssistant.Controls
{
    public partial class CopyableControl : UserControl
    {
        public static readonly DependencyProperty ClickCopyableProperty =
            DependencyProperty.Register("ClickCopyable", typeof(ICommand), typeof(CopyableControl));

        public ICommand ClickCopyable
        {
            get { return (ICommand)GetValue(ClickCopyableProperty); }
            set { SetValue(ClickCopyableProperty, value); }
        }

        public static readonly DependencyProperty CopyableProperty =
            DependencyProperty.Register("Copyable", typeof(Copyable), typeof(CopyableControl));

        public Copyable Copyable
        {
            get { return (Copyable)GetValue(CopyableProperty); }
            set { SetValue(CopyableProperty, value); }
        }

        public CopyableControl()
        {
            InitializeComponent();
        }
    }
}
<UserControl x:Class="ClipboardAssistant.Controls.DefineCopyableControl" x:Name="defineCopyableControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="500">
    <Grid x:Name="MainGrid" Background="Blue">
        <Grid Width="200" Height="180">
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="10" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="20" />
                <RowDefinition Height="30" />
            </Grid.RowDefinitions>

            <Label Grid.Row="0" Content="Name" Foreground="White" />
            <TextBox Grid.Row="1" Text="{Binding Copyable.Name}" x:Name="tbN" />

            <Label Grid.Row="3" Content="Copyable Text" Foreground="White" />
            <TextBox Grid.Row="4" Text="{Binding Copyable.TextToCopy}" x:Name="tbTTC" />

            <DockPanel Grid.Row="6">
                <Button Width="70" Content="OK" DockPanel.Dock="Right" HorizontalAlignment="Right"
                        Command="{Binding DefinerOKClickCommand}"
                        CommandParameter="{Binding ElementName=defineCopyableControl}" />
            </DockPanel>
        </Grid>
    </Grid>
</UserControl>

命令:

public partial class DefineCopyableControl : UserControl
{
    public static readonly DependencyProperty CopyableProperty =
        DependencyProperty.Register("Copyable", typeof(Copyable), typeof(DefineCopyableControl));

    public Copyable Copyable
    {
        get { return (Copyable)GetValue(CopyableProperty); }
        set { SetValue(CopyableProperty, value); }
    }

    public DefineCopyableControl()
    {
        InitializeComponent();
    }
}

设定:

namespace ClipboardAssistant.ViewModels.Commands
{
    public class CopyableClickCommand : ICommand
    {
        public ClipboardAssistantViewModel ViewModel { get; set; }

        public CopyableClickCommand(ClipboardAssistantViewModel viewModel)
        {
            ViewModel = viewModel;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            Copyable cp = (Copyable)parameter;

            ViewModel.EditCopyable(cp);
        }
    }
}

namespace ClipboardAssistant.ViewModels.Commands
{
    public class DefinerOKClickCommand : ICommand
    {
        public DefineCopyableViewModel ViewModel { get; set; }

        public DefinerOKClickCommand(DefineCopyableViewModel viewModel)
        {
            ViewModel = viewModel;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            ViewModel.EditCopyable();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我假设您使用的是Visual Studio。在这种情况下,在“我的项目”中,您是否在设置选项卡中列出了设置?

在我尝试以编程方式创建/保存/更新设置时,我遇到了同样的问题,并且在我在“设置”标签中创建设置之前一直没有成功。一旦完成,我就可以根据需要进行保存。

您只需使用

leftTextView

希望这有帮助!