Как реализовать сохранение пользователем разметки XAML?
Всем привет!
Проект WPF.
Собственно, хочу узнать как лучше(и можно ли вообще) такое реализовать. Т.е, например, пользователь по нажатию кнопки добавляет текстовое поле и при следующем запуске программы это поле уже будет в окне.
Были мысли в сторону того, чтобы сохранять разметку в файл xml, а потом подставлять ее в разметку xaml, но не нашел как.
Заранее спасибо!
Ответы (1 шт):
XAML разметка - это нечно статичное, то что вы создаете при реализации приложения. Она не изменяется во время его работы. Конечно, техническая возможность распарсить XAML и загрузить из него интерфейс есть, но в этом нет никакого практического смысла, к тому же это не просто.
Но если вам интересно, как именно загружается XAML разметка, поставьте курсор на InitializeComponent() и нажмите F12, увидите исходный код загрузчика окна.
Если вам нужна куча текстбоксов, а данные для текстбокса - это строка, то вам нужна коллекция строк. Есть в дотнете особая коллекция ObservableCollection, состав которой интерфейс умеет автоматически отслеживать. То есть вы создаете в ней элемент, и интерфейс тут же реагирует на эти изменения. И есть простой контрол, который умеет работать с такими коллекциями - ItemsControl. Чтобы их подружить вместе, нужно выполнить привязку данных коллекции к этому контролу. За это отвечает Binding.
Привязка возможна только к публичным свойствам. Давайте создадим такое свойство, например прямо в классе MainWindow.
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>();
Далее в XAML разметке нужно реализовать вот такую конструкцию
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
В таком виде работать не будет, а чтобы заработало, надо в конструкторе окна назначить DataContext, то есть указать место, где Binding должен искать данные.
InitializeComponent();
DataContext = this;
Вот теперь все работает. Например если вы захотите добавить элемент, надо просто сделать вот так.
Items.Add(string.Empty);
И тут же появится текстбокс.
Чтобы сохранить данные, можно использовать сериализацию коллекции, например в JSON.
File.WriteAllText("file.json", JsonSerializer.Serialize(Items));
А вот чтобы загрузить, есть нюанс, без реализации INotifyPropertyChanged (это отдельная история, но копать вам надо именно туда), присваивание Items можно делать только в конструкторе, в противном случае привязка будет разорвана, и интерфейс просто потеряет данные. Поэтому придется добавлять элементы, а не пересоздавать коллекцию.
Items.Clear();
string[] items = JsonSerializer.Deserialize<string[]>(File.ReadAllText("file.json"));
foreach (string item in items)
{
Items.Add(item);
}
Если это надо делать при загрузке приложения, то лучше этот код разместить в обработчике события Window.Loaded. Не пишите в конструкторе окна свой код, ну кроме того что я выше про DataContext указал.
Это очень сильно упрощенный пример, чтобы двигаться дальше, вам нужно научиться создавать модели данных (классы для данных) и познакомиться с INotifyPropertyChanged. А чтобы эти все знания научиться правильно применять - изучите шаблон проектирования MVVM.