c # - cách tiếp cận để lưu cài đặt người dùng trong ứng dụng WPF?


84

Bạn đề xuất cách tiếp cận nào đối với cài đặt người dùng liên tục trong ứng dụng WPF windows (máy tính để bàn)? Lưu ý rằng ý tưởng là người dùng có thể thay đổi cài đặt của họ tại thời điểm chạy và sau đó có thể đóng ứng dụng, sau đó khi khởi động ứng dụng sau đó, ứng dụng sẽ sử dụng cài đặt hiện tại. Hiệu quả sau đó nó sẽ xuất hiện như thể cài đặt ứng dụng không thay đổi.

Q1 - Cơ sở dữ liệu hoặc cách tiếp cận khác? Tôi có một cơ sở dữ liệu sqlite mà tôi sẽ sử dụng dù sao, do đó sử dụng một bảng trong cơ sở dữ liệu sẽ tốt như bất kỳ cách tiếp cận nào?

Q2 - Nếu Cơ sở dữ liệu: Thiết kế bảng cơ sở dữ liệu nào? Một bảng với các cột với nhiều loại dữ liệu khác nhau mà người ta có thể có (ví dụ string, long, DateTimevv) HOẶC chỉ là một bảng với một chuỗi cho giá trị khi mà bạn phải serialize và de-serialize các giá trị? Tôi nghĩ cách đầu tiên sẽ dễ dàng hơn, và nếu không có nhiều cài đặt thì chi phí không nhiều?

Q3 - Có thể sử dụng Cài đặt ứng dụng cho việc này không? Nếu vậy, có bất kỳ nhiệm vụ đặc biệt nào được yêu cầu để kích hoạt tính năng ổn định ở đây không? Ngoài ra, điều gì sẽ xảy ra liên quan đến việc sử dụng giá trị "mặc định" trong trình thiết kế Cài đặt ứng dụng trong trường hợp này? Liệu mặc định có ghi đè lên bất kỳ cài đặt nào đã được lưu giữa khi chạy ứng dụng không? (hoặc bạn sẽ KHÔNG sử dụng giá trị mặc định)


@ Tất cả người dùng mới Sẽ được ưu tiên hơn nếu bạn có thể đăng các câu hỏi riêng biệt thay vì kết hợp các câu hỏi của bạn thành một. Bằng cách đó, nó giúp những người trả lời câu hỏi của bạn và cả những người khác đang tìm kiếm ít nhất một trong những câu hỏi của bạn. Cảm ơn!
Hille

Câu trả lời:


80

Bạn có thể sử dụng Cài đặt ứng dụng cho việc này, sử dụng cơ sở dữ liệu không phải là lựa chọn tốt nhất khi xem xét thời gian tiêu tốn để đọc và ghi cài đặt (đặc biệt nếu bạn sử dụng dịch vụ web).

Dưới đây là một số liên kết giải thích cách đạt được điều này và sử dụng chúng trong WPF -

Cài đặt người dùng trong WPF

Mẹo WPF nhanh: Làm thế nào để liên kết với các tài nguyên và cài đặt ứng dụng WPF?

Một cửa sổ có thể cấu hình cho WPF


22

Cập nhật : Ngày nay tôi sẽ sử dụng JSON.

Tôi cũng thích đi với tuần tự hóa tệp. Các tệp XML phù hợp với hầu hết các yêu cầu. Bạn có thể sử dụng bản ApplicationSettingsdựng nhưng chúng có một số hạn chế và một hành vi được xác định nhưng (đối với tôi) rất kỳ lạ nơi chúng được lưu trữ. Tôi đã sử dụng chúng rất nhiều và chúng hoạt động. Nhưng nếu bạn muốn có toàn quyền kiểm soát cách thức và nơi lưu trữ chúng, tôi sử dụng cách tiếp cận khác.

  1. Tạo lớp học Ở đâu đó với tất cả các cài đặt của bạn. Tôi đặt tên cho nóMySettings
  2. Triển khai Lưu và Đọc để bền bỉ
  3. Sử dụng chúng trong mã ứng dụng của bạn

Ưu điểm:

  • Cách tiếp cận rất đơn giản.
  • Một lớp cho Cài đặt. Tải xuống. Tiết kiệm.
  • Tất cả các Cài đặt của bạn đều an toàn.
  • Bạn có thể đơn giản hóa hoặc mở rộng logic theo nhu cầu của mình (Tạo phiên bản, nhiều Hồ sơ cho mỗi người dùng, v.v.)
  • Nó hoạt động rất tốt trong mọi trường hợp (Cơ sở dữ liệu, WinForms, WPF, Dịch vụ, v.v.)
  • Bạn có thể xác định nơi lưu trữ các tệp XML.
  • Bạn có thể tìm thấy chúng và thao tác chúng bằng mã hoặc thủ công
  • Nó hoạt động cho bất kỳ phương pháp triển khai nào mà tôi có thể tưởng tượng.

Nhược điểm: - Bạn phải suy nghĩ về nơi lưu trữ các tập tin cài đặt của mình. (Nhưng bạn chỉ có thể sử dụng thư mục cài đặt của mình)

Đây là một ví dụ đơn giản (không được thử nghiệm) -

public class MySettings
{
    public string Setting1 { get; set; }
    public List<string> Setting2 { get; set; }

    public void Save(string filename)
    {
        using (StreamWriter sw = new StreamWriter(filename))
        {
            XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
            xmls.Serialize(sw, this);
        }
    }
    public MySettings Read(string filename)
    {
        using (StreamReader sw = new StreamReader(filename))
        {
            XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
            return xmls.Deserialize(sw) as MySettings;
        }
    }
}

Và đây là cách sử dụng nó. Có thể tải các giá trị mặc định hoặc ghi đè chúng bằng cài đặt của người dùng bằng cách chỉ cần kiểm tra xem cài đặt của người dùng có tồn tại hay không:

public class MyApplicationLogic
{
    public const string UserSettingsFilename = "settings.xml";
    public string _DefaultSettingspath = 
        Assembly.GetEntryAssembly().Location + 
        "\\Settings\\" + UserSettingsFilename;

    public string _UserSettingsPath = 
        Assembly.GetEntryAssembly().Location + 
        "\\Settings\\UserSettings\\" + 
        UserSettingsFilename;

    public MyApplicationLogic()
    {
        // if default settings exist
        if (File.Exists(_UserSettingsPath))
            this.Settings = Settings.Read(_UserSettingsPath);
        else
            this.Settings = Settings.Read(_DefaultSettingspath);
    }
    public MySettings Settings { get; private set; }

    public void SaveUserSettings()
    {
        Settings.Save(_UserSettingsPath);
    }
}

có thể ai đó lấy cảm hứng từ cách tiếp cận này. Đây là cách tôi làm bây giờ trong nhiều năm và tôi khá hài lòng với điều đó.


1
Đối với nhược điểm, sẽ là bạn không có trình thiết kế cài đặt nữa nên sẽ hơi kém thân thiện với người dùng khi cả hai đều hoạt động.
Phil1970

3
Hoàn toàn đồng ý về "hành vi rất kỳ lạ nơi chúng được lưu trữ", tôi đang sử dụng cách tiếp cận của bạn chính vì điều này. +1.
Hannish

Nếu bạn có câu hỏi MỚI, vui lòng đặt câu hỏi bằng cách nhấp vào nút Đặt câu hỏi .
Mat

12

Bạn có thể lưu trữ thông tin cài đặt của mình dưới Stringsdạng XML trong Settings.Default. Tạo một số lớp để lưu trữ dữ liệu cấu hình của bạn và đảm bảo chúng [Serializable]. Sau đó, với các trình trợ giúp sau, bạn có thể tuần tự hóa các phiên bản của các đối tượng này - hoặc List<T>(hoặc mảng T[], v.v.) của chúng - thành String. Lưu trữ từng chuỗi khác nhau này vào Settings.Defaultvị trí tương ứng của riêng nó trong ứng dụng WPF của bạn Settings.

Để khôi phục các đối tượng vào lần tiếp theo ứng dụng khởi động, hãy đọc Settingschuỗi quan tâm và Deserializeđến loại mong đợi T(lần này phải được chỉ định rõ ràng làm đối số loại Deserialize<T>).

public static String Serialize<T>(T t)
{
    using (StringWriter sw = new StringWriter())
    using (XmlWriter xw = XmlWriter.Create(sw))
    {
        new XmlSerializer(typeof(T)).Serialize(xw, t);
        return sw.GetStringBuilder().ToString();
    }
}

public static T Deserialize<T>(String s_xml)
{
    using (XmlReader xw = XmlReader.Create(new StringReader(s_xml)))
        return (T)new XmlSerializer(typeof(T)).Deserialize(xw);
}

6

Cách tiếp cận điển hình nhất trong thời gian dài cho câu hỏi này là: Lưu trữ biệt lập.

Tuần tự hóa trạng thái điều khiển của bạn thành XML hoặc một số định dạng khác (đặc biệt dễ dàng nếu bạn đang lưu Thuộc tính phụ thuộc bằng WPF), sau đó lưu tệp vào bộ nhớ riêng của người dùng.

Nếu bạn muốn thực hiện lộ trình cài đặt ứng dụng, tôi đã tự mình thử một cái gì đó tương tự ... mặc dù cách tiếp cận dưới đây có thể dễ dàng được điều chỉnh để sử dụng Isolated Storage:

class SettingsManager
{
    public static void LoadSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        EnsureProperties(sender, savedElements);
        foreach (FrameworkElement element in savedElements.Keys)
        {
            try
            {
                element.SetValue(savedElements[element], Properties.Settings.Default[sender.Name + "." + element.Name]);
            }
            catch (Exception ex) { }
        }
    }

    public static void SaveSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        EnsureProperties(sender, savedElements);
        foreach (FrameworkElement element in savedElements.Keys)
        {
            Properties.Settings.Default[sender.Name + "." + element.Name] = element.GetValue(savedElements[element]);
        }
        Properties.Settings.Default.Save();
    }

    public static void EnsureProperties(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        foreach (FrameworkElement element in savedElements.Keys)
        {
            bool hasProperty =
                Properties.Settings.Default.Properties[sender.Name + "." + element.Name] != null;

            if (!hasProperty)
            {
                SettingsAttributeDictionary attributes = new SettingsAttributeDictionary();
                UserScopedSettingAttribute attribute = new UserScopedSettingAttribute();
                attributes.Add(attribute.GetType(), attribute);

                SettingsProperty property = new SettingsProperty(sender.Name + "." + element.Name,
                    savedElements[element].DefaultMetadata.DefaultValue.GetType(), Properties.Settings.Default.Providers["LocalFileSettingsProvider"], false, null, SettingsSerializeAs.String, attributes, true, true);
                Properties.Settings.Default.Properties.Add(property);
            }
        }
        Properties.Settings.Default.Reload();
    }
}

..... và ....

  Dictionary<FrameworkElement, DependencyProperty> savedElements = new Dictionary<FrameworkElement, DependencyProperty>();

public Window_Load(object sender, EventArgs e) {
           savedElements.Add(firstNameText, TextBox.TextProperty);
                savedElements.Add(lastNameText, TextBox.TextProperty);

            SettingsManager.LoadSettings(this, savedElements);
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SettingsManager.SaveSettings(this, savedElements);
        }

5

Ngoài cơ sở dữ liệu, bạn cũng có thể có các tùy chọn sau để lưu các cài đặt liên quan đến người dùng

  1. đăng ký theo HKEY_CURRENT_USER

  2. trong một tệp trong AppDatathư mục

  3. sử dụng Settingstệp trong WPF và bằng cách đặt phạm vi của nó là Người dùng


2
Đề xuất 1 là lý do tại sao Ứng dụng làm chậm Windows, tốt hơn là không điền các khóa đăng ký bằng một thứ gì đó tốt hơn được thực hiện trong IMO tệp.
Bảng điều khiển

1
@Console, ghi tệp trên ổ đĩa làm chậm (mòn) SSD, ghi dữ liệu trong cơ sở dữ liệu làm chậm cơ sở dữ liệu. Lựa chọn của bạn sau đó là gì? Windows registry là dự định được sử dụng như một trong những nơi để lưu các thiết lập .
Sinatr

1
Bạn nói đúng, tôi nghĩ điều quan trọng là phải đề cập đến việc đăng ký có một số nhược điểm nếu mọi ứng dụng lưu tùy chọn người dùng hunderd ở đó.
Bảng điều khiển

@Sinatr Ban đầu, sổ đăng ký được thiết kế cho mục đích đó ... nhưng nó không được thiết kế để xử lý lượng lớn dữ liệu nên tại một số thời điểm trong lịch sử, Microsoft đã khuyến nghị ngừng sử dụng nó. Theo những gì tôi biết, Windows tải toàn bộ sổ đăng ký khi đăng nhập và cũng sẽ tạo bản sao để chuyển vùng hoặc để có thể tải cấu hình tốt đã biết cuối cùng sau một sự cố lớn. Do đó việc sử dụng sổ đăng ký sẽ ảnh hưởng đến hệ thống ngay cả khi ứng dụng chưa bao giờ được sử dụng.
Phil1970

Ngoài ra, sổ đăng ký có giới hạn kích thước và nếu nó vẫn được ứng dụng sử dụng, có thể giới hạn đó sẽ bị vượt quá trên hầu hết các máy tính. Cơ quan đăng ký được thiết kế vào thời điểm mà hệ thống có ít bộ nhớ MB hơn máy tính hiện nay tính bằng GB. Sổ đăng ký không được thiết kế quá lớn và do đó, mặc dù các giới hạn đã tăng lên, nhưng nó không được tối ưu hóa cho nhu cầu hiện tại của chúng tôi.
Phil1970

3

Theo kinh nghiệm của tôi, lưu trữ tất cả các cài đặt trong bảng cơ sở dữ liệu là giải pháp tốt nhất. Thậm chí đừng lo lắng về hiệu suất. Cơ sở dữ liệu ngày nay rất nhanh và có thể dễ dàng lưu trữ hàng nghìn cột trong một bảng. Tôi đã học được điều này một cách khó khăn - trước khi tôi bắt đầu mê hoặc hạ cánh - cơn ác mộng. Lưu trữ nó trong tệp cục bộ hoặc sổ đăng ký có một vấn đề lớn - nếu bạn phải hỗ trợ ứng dụng của mình và máy tính bị tắt - người dùng không ở phía trước nó - bạn không thể làm gì .... nếu cài đặt trong DB - bạn có thể đã thay đổi chúng và viola chưa kể rằng bạn có thể so sánh các cài đặt ....


Và việc lưu trữ chúng từ xa cũng có một vấn đề lớn khi kết nối không khả dụng ... Nhiều ứng dụng được viết để hoạt động trực tuyến có trải nghiệm kém lý tưởng khi làm việc ngoại tuyến hoặc đôi khi có lỗi khiến một số chức năng không hoạt động ngoại tuyến ngay cả khi cần không có bất kỳ tác động nào ngoài việc "theo dõi" cách thiết bị được sử dụng.
Phil1970

1

Tôi thường làm điều này bằng cách xác định một Serializablelớp cài đặt [ ] tùy chỉnh và chỉ cần tuần tự hóa nó vào đĩa. Trong trường hợp của bạn, bạn có thể dễ dàng lưu trữ nó như một chuỗi blob trong cơ sở dữ liệu SQLite của mình.


0
  1. Ở tất cả những nơi tôi đã làm việc, cơ sở dữ liệu là bắt buộc vì hỗ trợ ứng dụng. Như Adam đã nói, người dùng có thể không có mặt tại bàn làm việc của anh ấy hoặc máy có thể tắt, hoặc bạn có thể muốn nhanh chóng thay đổi cấu hình của ai đó hoặc gán cho người mới tham gia một cấu hình mặc định (hoặc của thành viên trong nhóm).

  2. Nếu các cài đặt có khả năng tăng lên khi các phiên bản mới của ứng dụng được phát hành, bạn có thể muốn lưu trữ dữ liệu dưới dạng các đốm màu mà sau đó ứng dụng có thể được khử trên mặt đất. Điều này đặc biệt hữu ích nếu bạn sử dụng một cái gì đó như Prism khám phá các mô-đun, vì bạn không thể biết cài đặt nào mà một mô-đun sẽ trả về. Các đốm màu có thể được khóa bằng khóa tổng hợp tên người dùng / máy. Bằng cách đó, bạn có thể có các cài đặt khác nhau cho mọi máy.

  3. Tôi đã không sử dụng lớp Cài đặt có sẵn nhiều nên tôi sẽ kiêng nhận xét. :)


0

Tôi muốn sử dụng tệp điều khiển xml dựa trên một lớp cho ứng dụng WPF trên máy tính để bàn VB.net của mình. Đoạn mã trên để làm điều này tất cả trong một là tuyệt vời và giúp tôi đi đúng hướng. Trong trường hợp có ai đang tìm kiếm giải pháp VB.net thì đây là lớp tôi đã xây dựng:

Imports System.IO
Imports System.Xml.Serialization

Public Class XControl

Private _person_ID As Integer
Private _person_UID As Guid

'load from file
Public Function XCRead(filename As String) As XControl
    Using sr As StreamReader = New StreamReader(filename)
        Dim xmls As New XmlSerializer(GetType(XControl))
        Return CType(xmls.Deserialize(sr), XControl)
    End Using
End Function

'save to file
Public Sub XCSave(filename As String)
    Using sw As StreamWriter = New StreamWriter(filename)
        Dim xmls As New XmlSerializer(GetType(XControl))
        xmls.Serialize(sw, Me)
    End Using
End Sub

'all the get/set is below here

Public Property Person_ID() As Integer
    Get
        Return _person_ID
    End Get
    Set(value As Integer)
        _person_ID = value
    End Set
End Property

Public Property Person_UID As Guid
    Get
        Return _person_UID
    End Get
    Set(value As Guid)
        _person_UID = value
    End Set
End Property

End Class
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.