2016-08-09 8 views
-1

CopyablesというCopyable(カスタムクラス)のObservableCollectionのユーザー設定からデータを取得するWPF MVVMアプリケーションがあります。メインビューモデル(ClipboardAssistantViewModel)内で、CollectionViewSourceのソースをCopyablesに設定しました。これは、メインビュー(MainWindow)のItemsControlにバインドされます。こののDataTemplateは、基本的にボタンですが、データとコマンドをバインドできるプロパティが付いている「CopyableControl」というユーザーコントロールです。このメソッドが初めて呼び出されたときに初めてユーザー設定が保存されるのはなぜですか?

ユーザがCopyableControlをクリックすると、ビューモデル(DefineCopyableViewModel)はClipboardAssistantViewModelにおけるそれらのObservableCollectionに添加し、そのコレクションをMainWindowItemsControlに結合されます。これのDataTemplateは、DefineCopyableControlと呼ばれるUserControlであり、クリックされたCopyableに関連する現在の値がDefineCopyableControlのテキストボックスにバインドされて編集されるように設定されています。

私の問題:のみ最初の実行に取り組んでいますDefineCopyableViewModelEditCopyable()における方法は、(その仕事はどんな編集が行われていると、ユーザーが「OK」ををクリックした後、ユーザー設定を保存することです)があります。 CopyableControlをクリックして編集したら、「OK」をクリックしてもう一度クリックしてもう一度編集し、「OK」をクリックしてアプリケーションを閉じてもう一度開くと、最初の編集だけが完了しています保存されました(UIが編集された値で両方の時間で更新された場合でも)。データバインディングを「リフレッシュ」する必要があると思われます。私の知見はこのコードの中のコメントを参照してください。

次のように私のコードは次のとおりです。

モデル:

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

のviewmodels:

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

メインウィンドウ:

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

CopyableControl:

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

DefineCopyableControl:

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

セッティング:

namespace ClipboardAssistant.Properties { 


    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 

     private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 

     public static Settings Default { 
      get { 
       return defaultInstance; 
      } 
     } 

     [global::System.Configuration.UserScopedSettingAttribute()] 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 
     public global::System.Collections.ObjectModel.ObservableCollection<ClipboardAssistant.Models.Copyable> Copyables { 
      get { 
       return ((global::System.Collections.ObjectModel.ObservableCollection<ClipboardAssistant.Models.Copyable>)(this["Copyables"])); 
      } 
      set { 
       this["Copyables"] = value; 
      } 
     } 
    } 
} 
+0

私は、デザイナーが提供する 'Settings'オブジェクトに' ObservableCollection 'のようなものを保存するように納得させるのは苦痛だと知っています。私にそうする必要がある質問。あなたのコード例は、設定のコピー/ペーストのストレート実装なしでは不完全です。さらに、私は上記のすべてが実際に問題を再現することが本当に必要であると真剣に疑う。コード例も最小限ではないようです。 –

+0

コード例に設定を追加しました。 –

答えて

1

私はあなたがVisual Studioを使用していると仮定しています。その場合、マイプロジェクトでは、[設定]タブに設定がありますか?

設定を作成/保存/更新するときに同じ問題が発生しましたが、設定タブで設定を作成するまでは問題はありませんでした。それが完了したら、私は必要に応じて私の節約をすることができました。

ザ・あなただけのこのことができます

MySettings.Default.SettingName = value 
MySettings.Default.Save() 

希望を使用します!

+0

コレクションは[設定]タブにありますが、このようなことをしなければなりませんでしたが、[http://stackoverflow.com/questions/2890271/how-to-save-a-liststring-on-settings-default](http: //stackoverflow.com/questions/2890271/how-to-save-a-liststring-on-settings-default) - ObservableCollection を有効なタイプとして選択するための[設定]タブを表示するには(私はxmlファイル)。また、実際の設定を自分のメソッドの値に設定する必要はありません。データバインディングはそれを処理する必要があります(最初の実行時に行う)。 –

関連する問題