2015-09-23 18 views
7

Giả sử rằng tôi cần lưu trữ bất kỳ mảng nào trong tiện ích mở rộng vừa được tạo từ mẫu.Lưu trữ mảng trong các tùy chọn bằng cách sử dụng DialogPage

tôi vừa tạo ra dự án VSIX mới, thêm VSPackage với nó, sau đó thêm vào trang tùy chọn lưới (DialogPage). Sau đó, tôi làm theo hướng dẫn từ câu trả lời cho một câu hỏi tương tự: DialogPage - string array not persisted.

Và, cho các mục đích trình diễn, chúng ta hãy cũng thêm int[] mảng và đồng bằng int với tùy chỉnh loại chuyển đổi.

// [standard attributes] 
[ProvideOptionPage(typeof(OptionPageGrid), 
"My Category", "My Grid Page", 0, 0, true)] 
public sealed class FooBarVSPackage : Package 
{ 
    // standard code 
} 

public class OptionPageGrid : DialogPage 
{ 
    // [typical attributes] 
    [TypeConverter(typeof(StringArrayConverter))] 
    public string[] Foos 
    { get; set; } 

    // [typical attributes] 
    [TypeConverter(typeof(CustomIntConverter))] 
    public int Bar 
    { get; set; } 

    // [typical attributes] 
    [TypeConverter(typeof(IntArrayConverter))] 
    public int[] Bazes 
    { get; set; } 
} 

class StringArrayConverter : TypeConverter 
{ 
    // exact copy of code from similar question/answer mentioned above 
} 

public class IntArrayConverter : TypeConverter 
{ 
    private const string delimiter = "#@#"; 

    // CanConvertFrom, ConvertTo, etc. overridden in similar fashion 
} 

public class CustomIntConverter : TypeConverter 
{ 
    // CanConvertFrom() overridden 
    // CanConvertTo() overridden 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     var v = value as string; 
     return int.Parse(v.TrimStart('*')); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     var v = (int)value; 
     return v.ToString().PadLeft(25, '*'); 
    } 
} 

Khi tôi sửa những lựa chọn, tôi có thể thấy rằng bộ chuyển đổi thực sự hoạt động: Type Converter really works

Nhưng sau khi tôi mở lại nó, hai trong số các giá trị biến mất! Chỉ đồng bằng int được duy trì: Array values are lost, but plain int persisted

Ngoài ra còn có một điều lạ: cách thức và cách thức gọi phương thức TypeConverter. CanConvertTo()không bao giờ được gọi là trong toàn bộ phiên. CanConvertFrom()ConvertTo() được gọi là thường xuyên và nhiều hơn hoặc ít hơn trong thời trang dự kiến. Và ConvertFrom() được gọi là chỉ khi biểu thị chuỗi của tùy chọn được chỉnh sửa trực tiếp, tức là không tham gia vào các tùy chọn tải/lưu!

Tôi không chắc chắn, nhưng nó cảm thấy một chút như int tùy chọn được lưu giữ như int và quay từ/vào string chỉ trong giao diện tùy chọn, trong khi mảng tùy chọn chỉ âm thầm không cố gắng để làm như vậy.

PS: Nếu bạn muốn trực tiếp chơi với ví dụ cá nhân, đây là một repo GitHub với dự án ví dụ trong câu hỏi: FooBarVSIXProject

Trả lời

7

Sau khi trải qua nhiều giờ cố gắng để sửa chữa bị hỏng “dễ sử dụng” cơ chế (hoặc chính nó là bị hỏng hoặc tài liệu của nó), tôi nhận ra rằng thay vì lãng phí thời gian, tôi nên có chỉ xuống một lớp trừu tượng xuống và làm chính xác những gì tôi muốn DialogPage cơ chế làm tự động.

Một hy vọng rằng DialogPage nên lưu/tải các chuỗi đại diện (thu được qua loại chuyển đổi) vào/từ User Settings Store (hoặc một cái gì đó như thế) khi nó SaveSettingsToStorage()LoadSettingsFromStorage() được gọi. Kể từ khi nó từ chối làm như vậy và các phương pháp đó là virtual, chúng ta có thể thực hiện chính xác rằng mình:

public class OptionPageGrid : DialogPage 
{ 
    const string collectionName = "FooBarVSIX"; 

    [Category("General")] 
    [DisplayName("Foos")] 
    [Description("Bla Foo Bla")] 
    // note that TypeConverter attribute is removed, 
    // because it's not relevant anymore 
    public string[] Foos 
    { get; set; } 

    // Bar and Bazes properties missed out to make this example shorter 

    public override void SaveSettingsToStorage() 
    { 
     base.SaveSettingsToStorage(); 

     var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider); 
     var userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); 

     if (!userSettingsStore.CollectionExists(collectionName)) 
      userSettingsStore.CreateCollection(collectionName); 

     var converter = new StringArrayConverter(); 
     userSettingsStore.SetString(
      collectionName, 
      nameof(Foos), 
      converter.ConvertTo(this.Foos, typeof(string)) as string); 
     // save Bazes in similar way 
    } 

    public override void LoadSettingsFromStorage() 
    { 
     base.LoadSettingsFromStorage(); 

     var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider); 
     var userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); 

     if (!userSettingsStore.PropertyExists(collectionName, nameof(Foos))) 
      return; 

     var converter = new StringArrayConverter(); 
     this.Foos = converter.ConvertFrom(
      userSettingsStore.GetString(collectionName, nameof(Foos))) as string[]; 
     // load Bazes in similar way 
    } 
} 

Bây giờ, tất nhiên, nếu bạn làm theo cách này, bạn không cần phải viết và sử dụng TypeConverter, thực sự. Bạn chỉ có thể nhúng logic tuần tự hóa vào đúng các phương thức đó hoặc bất kỳ đâu.

Ngoài ra, bạn có thể tuần tự hóa dữ liệu của mình ngay thành định dạng nhị phân và sử dụng SetMemoryStream() để lưu.

+2

Đây là lỗi trong VS 2015. MS đã thay đổi đáng kể logic trong DialogPage.LoadSettingsFromStorage và SaveSettingsToStorage giữa VS 2013 và VS 2015, và chúng đã phá vỡ LoadSettingsFromStorage cho các thuộc tính sử dụng TypeConverters. Tôi đã báo cáo điều này thông qua hộp thoại "Báo cáo sự cố" của VS 2015 và thông qua Kết nối, vì vậy có thể họ sẽ khắc phục sự cố này cuối cùng. Trong khi chờ đợi, tôi cũng phải giải quyết nó bằng các ghi đè như bạn đã làm. Lưu ý: TypeConverters vẫn hữu ích cho việc chỉnh sửa các giá trị trong PropertyGrid. Ngoài ra, lỗi MS là trong DialogPage.SetPropertyValue, mà chỉ cần gọi Convert.ChangeType bây giờ. –

Các vấn đề liên quan