WPF 응용 프로그램에서 사용자 설정을 저장하는 방법?
WPF Windows (데스크톱) 애플리케이션에서 사용자 설정을 유지하기 위해 어떤 접근 방식을 권장합니까? 아이디어는 사용자가 런타임에 설정을 변경 한 다음 응용 프로그램을 닫을 수 있으며 나중에 응용 프로그램을 시작할 때 응용 프로그램이 현재 설정을 사용할 수 있다는 것입니다. 실제로 응용 프로그램 설정이 변경되지 않는 것처럼 나타납니다.
Q1-데이터베이스 또는 기타 접근 방식? 어쨌든 사용할 sqlite 데이터베이스가 있으므로 데이터베이스에서 테이블을 사용하는 것이 어떤 접근 방식만큼 좋을까요?
Q2-If Database : 어떤 데이터베이스 테이블 디자인입니까? 하나가있을 수 있음을 다른 데이터 형식의 열이 하나 개의 테이블 (예를 들면 string
, long
, DateTime
등) 또는 당신이 직렬화 및 역 직렬화 값으로이있는시 값에 대한 문자열을 그냥 테이블? 첫 번째가 더 쉬울 것이라고 생각하고 설정이 많지 않으면 오버 헤드가 많지 않습니까?
Q3-이를 위해 애플리케이션 설정을 사용할 수 있습니까? 그렇다면 여기에서 지속성을 활성화하는 데 필요한 특별한 작업이 있습니까? 또한이 경우 응용 프로그램 설정 디자이너의 "기본값"값 사용과 관련하여 어떤 일이 발생합니까? 기본값이 응용 프로그램 실행 사이에 저장된 모든 설정을 무시합니까? (또는 기본값을 사용하지 않아도됩니다)
이를 위해 응용 프로그램 설정 을 사용할 수 있습니다. 데이터베이스를 사용하는 것은 설정을 읽고 쓰는 데 걸리는 시간을 고려할 때 최선의 선택이 아닙니다 (특히 웹 서비스를 사용하는 경우).
다음은이를 달성하고 WPF에서 사용하는 방법을 설명하는 몇 가지 링크입니다.
빠른 WPF 팁 : WPF 애플리케이션 리소스 및 설정에 바인딩하는 방법은 무엇입니까?
.NET Strings
Framework에서 XML 로 설정 정보를 저장할 수 있습니다 Settings.Default
. 구성 데이터를 저장할 일부 클래스를 만들고 [Serializable]
. 그런 다음 다음 도우미를 사용하여 이러한 개체의 인스턴스 List<T>
(또는 배열 T[]
등)를 String
. 이러한 다양한 문자열 각각을 Settings.Default
WPF 애플리케이션의 Settings
.
다음에 앱이 시작될 때 객체를 복구하려면 Settings
관심 있는 문자열과 Deserialize
예상 유형을 읽습니다 T
(이번에는에 대한 유형 인수로 명시 적으로 지정해야 함 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);
}
업데이트 : 요즘은 JSON을 사용합니다.
또한 파일 직렬화를 선호합니다. XML 파일은 대부분 모든 요구 사항에 적합합니다. ApplicationSettings
빌드를 사용할 수 있지만 여기에는 몇 가지 제한 사항과 정의되어 있지만 저장 위치에 매우 이상한 동작이 있습니다. 나는 그것들을 많이 사용했고 그들은 작동합니다. 그러나 저장 방법과 위치를 완전히 제어하려면 다른 접근 방식을 사용합니다.
- 모든 설정으로 어딘가에 수업을 만드십시오. 나는 그것을 명명했다
MySettings
- 지속성을 위해 저장 및 읽기 구현
- 응용 프로그램 코드에서 사용
장점 :
- 매우 간단한 접근 방식입니다.
- 설정을위한 하나의 클래스. 하중. 저장.
- 모든 설정은 유형이 안전합니다.
- 논리를 단순화하거나 필요에 맞게 확장 할 수 있습니다 (버전 관리, 사용자 당 여러 프로필 등).
- 어떤 경우에도 매우 잘 작동합니다 (데이터베이스, WinForms, WPF, 서비스 등).
- XML 파일을 저장할 위치를 정의 할 수 있습니다.
- 코드 또는 수동으로 찾아서 조작 할 수 있습니다.
- 내가 상상할 수있는 모든 배포 방법에서 작동합니다.
단점 :-설정 파일을 저장할 위치를 생각해야합니다. (하지만 설치 폴더 만 사용할 수 있습니다.)
다음은 간단한 예입니다 (테스트되지 않음).
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;
}
}
}
그리고 그것을 사용하는 방법이 있습니다. 사용자 설정이 있는지 확인하여 기본값을로드하거나 사용자 설정으로 재정의 할 수 있습니다.
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);
}
}
누군가이 접근 방식에서 영감을 얻었을 수도 있습니다. 이것이 제가 수년 동안하는 방식이며 저는 그것에 대해 매우 만족합니다.
이 질문에 대한 장기 실행 중 가장 일반적인 접근 방식은 격리 된 저장소입니다.
컨트롤 상태를 XML 또는 다른 형식으로 직렬화 한 다음 (특히 WPF로 종속성 속성을 저장하는 경우 쉽게) 파일을 사용자의 격리 된 저장소에 저장합니다.
앱 설정 경로로 가고 싶다면 한 지점에서 비슷한 것을 시도했습니다 ... 아래 접근 방식은 격리 된 저장소를 사용하도록 쉽게 조정할 수 있습니다.
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();
}
}
.....과....
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);
}
데이터베이스와 별도로 사용자 관련 설정을 저장하기 위해 다음 옵션을 사용할 수도 있습니다.
아래에 레지스트리
HKEY_CURRENT_USER
AppData
폴더 의 파일Settings
WPF에서 파일을 사용 하고 범위를 사용자로 설정하여
In my experience storing all the settings in a database table is the best solution. Don't even worry about performance. Today's databases are fast and can easily store thousands columns in a table. I learned this the hard way - before I was serilizing/deserializing - nightmare. Storing it in local file or registry has one big problem - if you have to support your app and computer is off - user is not in front of it - there is nothing you can do.... if setings are in DB - you can changed them and viola not to mention that you can compare the settings....
I typically do this sort of thing by defining a custom [Serializable
] settings class and simply serializing it to disk. In your case you could just as easily store it as a string blob in your SQLite database.
In all the places I've worked, database has been mandatory because of application support. As Adam said, the user might not be at his desk or the machine might be off, or you might want to quickly change someone's configuration or assign a new-joiner a default (or team member's) config.
If the settings are likely to grow as new versions of the application are released, you might want to store the data as blobs which can then be deserialized by the application. This is especially useful if you use something like Prism which discovers modules, as you can't know what settings a module will return. The blobs could be keyed by username/machine composite key. That way you can have different settings for every machine.
I've not used the in-built Settings class much so I'll abstain from commenting. :)
I wanted to use an xml control file based on a class for my VB.net desktop WPF application. The above code to do this all in one is excellent and set me in the right direction. In case anyone is searching for a VB.net solution here is the class I built:
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
'Development Tip' 카테고리의 다른 글
스토리 보드에 인터페이스 설정이있는 Swift의 UIViewController에 대한 사용자 정의 초기화 (0) | 2020.11.11 |
---|---|
Visual Studio Code에서 올바른 들여 쓰기로 붙여 넣기 복사 설정 (0) | 2020.11.11 |
소켓 연결에 대한 추가 데이터 보내기 (0) | 2020.11.11 |
HTML5 범위에 대한 onChange 이벤트 (0) | 2020.11.11 |
Rails : schema.rb의 기능은 무엇입니까? (0) | 2020.11.11 |