0

INotifyPropertyChangedイベントを実装するクラスのserializationにいくつかの問題がありました。今私はdeserializationに問題がある以前のクラスの非直列化INotifiyPropertyChangedの実装

SerializationException when serializing instance of a class which implements INotifyPropertyChangedに推奨されているように(Binary Serialization of ViewModel (ObservableCollection)

を解決しました。

BinaryFormatter formatter = new BinaryFormatter();    
     FileStream fs_open = new FileStream(@"C:\Users\vm_user\Documents\Visual Studio 2015\testbin.txt", FileMode.Open); 
     ViewModels.MainViewModel mvm1 = (ViewModels.MainViewModel)formatter.Deserialize(fs_open); 
     fs_open.Close(); 

ようにそれをやったときdeserializedオブジェクトは、もはや任意のeventsを発射しないでください。

シリアライズ前と同じ機能を得るにはどうすればよいですか?それは、することができます

private ViewModels.WatchedFile refeshLoadedFiles(ViewModels.WatchedFile fileSource) 
    { 
     ViewModels.WatchedFile wf = new ViewModels.WatchedFile(fileSource.Name, fileSource.Path, fileSource.Tags, new ObservableCollection<ViewModels.WatchedFile>()); 
     foreach (ViewModels.WatchedFile subs in fileSource.Subs) 
     { 
      wf.Subs.Add(refeshLoadedFiles(subs)); 
     }    
     return wf; 
    } 

しかし、これはserializationの目標でcan't:

BinaryFormatter formatter = new BinaryFormatter(); 
     ViewModels.MainViewModel mvm1 = new ViewModels.MainViewModel(); 
     FileStream fs_open = new FileStream(@"C:\Users\vm_user\Documents\Visual Studio 2015\testbin.txt", FileMode.Open);    
     foreach (ViewModels.WatchedFile file in ((ViewModels.MainViewModel)formatter.Deserialize(fs_open)).WatchedFiles) 
     { 
      ViewModels.WatchedFile wf = new ViewModels.WatchedFile(file.Name, file.Path, file.Tags, new ObservableCollection<ViewModels.WatchedFile>()); 
      foreach (ViewModels.WatchedFile subs in file.Subs) 
      { 
       wf.Subs.Add(refeshLoadedFiles(subs)); 
      } 
      mvm1.WatchedFiles.Add(wf); 
     } 
     fs_open.Close(); 

とrefreshLoadedFiles:は、今のところ私はこれでそれを行いますか?私がそれをすれば、私はtypeと残りのすべてのテキストファイルをテキストファイルに書き込むことができます。

ありがとうございました。

これはViewModelに(編集)である:

namespace WatchedFile.ViewModels 
{ 
[Serializable()] 
public class ViewModelBase : INotifyPropertyChanged 
{ 
public event PropertyChangedEventHandler PropertyChanged; 

protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
} 
} 

[Serializable()] 
public class WatchedFile : ViewModelBase 
{ 
#region Name Property 
private String _name = default(String); 
public String Name 
{ 
    get { return _name; } 
    set 
    { 
     if (value != _name) 
     { 
      _name = value; 
      OnPropertyChanged(); 
     } 
    } 
} 
#endregion Name Property 

#region Path Property 
private String _path = default(String); 
public String Path 
{ 
    get { return _path; } 
    set 
    { 
     setDisplayImage(value); 
     if (value != _path) 
     { 
      _path = value; 
      OnPropertyChanged(); 

     } 
    } 
} 
#endregion Path Property 

#region Tags Property 
private ObservableCollection<Tag> _tags = new ObservableCollection<Tag>(); 
public ObservableCollection<Tag> Tags 
{ 
    get { return _tags; } 
    protected set 
    { 
     if (value != _tags) 
     { 
      _tags = value; 
      OnPropertyChanged(); 
     } 
    } 
} 
#endregion Tags Property 

#region Subs Property 
private ObservableCollection<WatchedFile> _subs = new ObservableCollection<WatchedFile>(); 
public ObservableCollection<WatchedFile> Subs 
{ 
    get { return _subs; } 
    protected set 
    { 
     setDisplayImage(Path); 
     if (value != _subs) 
     { 
      _subs = value; 
      _subs.CollectionChanged += _subs_CollectionChanged; 
      OnPropertyChanged(); 
     } 
    } 
} 

private void _subs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
{ 
    Subs = Sort(Subs); 
} 
#endregion Subs Property 

[NonSerialized()] 
private BitmapImage _displayImage = default(BitmapImage); 
public BitmapImage DisplayImage 
{ 
    get { return _displayImage; } 
    protected set 
    { 
     if (value != _displayImage) 
     { 
      _displayImage = value; 
      OnPropertyChanged(); 
     } 
    } 
} 

public WatchedFile(): this(string.Empty,string.Empty,new ObservableCollection<Tag>(),new ObservableCollection<WatchedFile>()) 
{          
} 

public WatchedFile(String name, String path, ObservableCollection<Tag> tags, ObservableCollection<WatchedFile> subitems) 
{ 
    Subs = WatchedFile.Sort(subitems); 
    Name = name; 
    Path = path; 
    Tags = tags; 
} 

public static ObservableCollection<WatchedFile> Sort(ObservableCollection<WatchedFile> files) 
{ 
    if (files == null) 
     return files; 
    ObservableCollection<WatchedFile> filesReturn = new ObservableCollection<ViewModels.WatchedFile>(); 
    WatchedFile[] sortedArray = files.ToArray(); 

    WatchedFile temp; 
    for (int j = 1; j <= sortedArray.Length - 1; j++) 
    { 
     for (int i = j; i > 0; i--) 
     { 
      if (sortedArray[i].Subs != null && sortedArray[i].Subs.Count > 1) 
      { 
       ObservableCollection<WatchedFile> subs = Sort(sortedArray[i].Subs); 
       sortedArray[i].Subs.Clear(); 
       foreach (WatchedFile f in subs) 
        sortedArray[i].Subs.Add(f); 
      } 

      if (sortedArray[i - 1].Subs != null && sortedArray[i - 1].Subs.Count > 1) 
      { 
       ObservableCollection<WatchedFile> subs = Sort(sortedArray[i - 1].Subs); 
       sortedArray[i - 1].Subs.Clear(); 
       foreach (WatchedFile f in subs) 
        sortedArray[i - 1].Subs.Add(f); 
      } 

      if ((sortedArray[i].Name).CompareTo(sortedArray[i - 1].Name) == -1) 
      { 
       temp = sortedArray[i]; 
       sortedArray[i] = sortedArray[i - 1]; 
       sortedArray[i - 1] = temp; 
      } 
      else 
       break; 
     } 
    } 
    filesReturn.Clear(); 
    foreach (WatchedFile f in sortedArray) 
     filesReturn.Add(f); 

    return filesReturn; 
} 
} 

[Serializable()] 
public class Tag 
{ 
public Tag(String value) 
{ 
    Value = value; 
} 
public String Value { get; private set; } 
} 

[Serializable()] 
public class MainViewModel : ViewModelBase 
{ 
public MainViewModel() 
{ 

} 

#region WatchedFiles Property   
private ObservableCollection<WatchedFile> _watchedFiles = new ObservableCollection<WatchedFile>(); 
public ObservableCollection<WatchedFile> WatchedFiles 
{ 
    get { return _watchedFiles; } 
    protected set 
    { 
     if (value != _watchedFiles) 
     { 
      _watchedFiles =WatchedFile.Sort(value);// value; 
      _watchedFiles.CollectionChanged += _watchedFiles_CollectionChanged; 
      OnPropertyChanged(); 
     } 
    } 
} 

private void _watchedFiles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
{ 
    WatchedFiles = WatchedFile.Sort(WatchedFiles); 
} 
#endregion WatchedFiles Property 
} 
} 

答えて

1

何もそれらに加入していないので、彼らは発生しません。 WPFでは、ビューまたはコントロールが読み込まれるときに、フレームワークはバックグラウンドでバインド中にサブスクライブします。パイプラインの別のステージでこれをやっているので、正しいステージでモデルをロードして、サブスクリプションが再び発生するようにするためのより良い方法を見つけなければなりません。もっと見ることなく言うのは難しいですが、これは非常に臭いです。これはコントロールかフルビューのデータコンテキストですか?

少なくとも、モデルの再バインドを強制します。それ以外の場合は、代わりにdtoをシリアル化してviewmodelに注入し、ビューをロードする前に状態を復元したり、メインビューモデルにdtoを渡して観察可能なプロパティにリバインドするメソッドを与えることができます。私が言ったように、あなたが本当にやっていることを見ることなく、言うことは難しいです。

+1

+1はDTOオプションに言及しています。シリアライゼーションにDTOを使用するようにこのシステムを再構築すれば、少しのグルーコードを必要とするだけで多くの頭痛を防ぐことができます。 –

+0

あなたは 'DTO'が何であるか説明できますか? (リンクや何かを追加しますか?)何かを変更するときに、少なくともセットのアクセサを使用しないでください。 'ViewModel'が' TreeView'にバインドされています。 – Thoms

+0

ビューモデルのポイントはビューを元に戻すことです.dtoは主に状態を移送するためのものです。 DTOは単なる財産バッグです。プロパティの束を持ち、動作しないオブジェクトです。私はしばしば、あなたが復元しようとしているオブジェクトのカプセル化された動作が、外部ソースに開く必要がないオブジェクトのような状況でこれらを使用します。この場合、DTOを使用してデータをVMにソートすることをソートします。すべての状態情報を含むDTOを渡して、VMが自身の状態を復元し、ビュー上のコントロールへのオブザーバブルの再バインドなどの任意の規則を適用できるようにする – Sinaesthetic

関連する問題