Чтение Xml файла с выводом данных в DataGridView в c#

Как выполнить чтение xml файла с выводом данных в DataGridView?

В этой статье хочу показать на простом примере, как можно выполнить чтение xml файла с выводом данных в DataGridView.

И так для начала создадим Windows Forms приложение на языке c# и добавим на форму два элемента управления: кнопку и DataGridView.

элемент DataGridView

Затем создадим xml файл, который, к примеру, пускай содержит следующую структуру:

<friends>
<friend id="1">
<name>Александр</name>
<age>25</age>
</friend>
<friend id="2">
<name>Николай</name>
<age>26</age>
</friend>
</friends>

После чего добавим xml файл в проект.

Для работы с xml файлами и документами необходимо добавить строку:

using System.Xml.Linq;

На этом подготовительная часть закончена, переходим к решению задачи.

И так сначала добавим метод CreateTable, с помощью него мы создадим таблицу с тремя колонками: id, name и age, в которой будем хранить значения элементов и атрибутов, содержащихся в xml файле.

private DataTable CreateTable()
{
//создаём таблицу
DataTable dt = new DataTable("Friends");
//создаём три колонки
DataColumn colID = new DataColumn("Id", typeof(Int32));
DataColumn colName = new DataColumn("Name", typeof(String));
DataColumn colAge = new DataColumn("Age", typeof(Int32));
//добавляем колонки в таблицу
dt.Columns.Add(colID);
dt.Columns.Add(colName);
dt.Columns.Add(colAge);
return dt;
}

Затем создадим метод ReadXml, с помощью которого мы будем выполнять сразу два действия: чтение xml файла и заполнение таблицы данными.

private DataTable ReadXml()
{
DataTable dt = null;
try
{
//загружаем xml файл
XDocument xDoc = XDocument.Load(@"../../имя файла.xml");
//создаём таблицу
dt = CreateTable();
DataRow newRow = null;
//получаем все узлы в xml файле
foreach (XElement elm in xDoc.Descendants("friend"))
{
//создаём новую запись
newRow = dt.NewRow();
//проверяем наличие атрибутов (если требуется)
if (elm.HasAttributes)
{
//проверяем наличие атрибута id
if (elm.Attribute("id") != null)
{
//получаем значение атрибута
newRow["id"] = int.Parse(elm.Attribute("id").Value);
}
}
//проверяем наличие xml элемента name
if (elm.Element("name") != null)
{
//получаем значения элемента name
newRow["name"] = elm.Element("name").Value;
}
if (elm.Element("age") != null)
{
newRow["age"] = int.Parse(elm.Element("age").Value);
}
//добавляем новую запись в таблицу
dt.Rows.Add(newRow);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return dt;
}

Таблица создана и заполнена. Теперь нам осталось только вывести данные в DataGridView.

private void button1_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = ReadXml();
}

результат

вывод данных

Если же Вам не хочется самостоятельно описывать логику работы с xml файлом, то тогда Вы можете решить данную задачу более простым способом:

DataSet ds = new DataSet("Friends");
ds.ReadXml(@"..//..//имя файла.xml");
dataGridView1.DataSource = ds.Tables[0];

Вместо указания индекса таблицы, Вы так же можете указать имя таблицы, например:

dataGridView1.DataSource = ds.Tables["friend"];

В этом примере мы сначала выполняем чтение xml файла, а затем выводим данные в DataGridView. Только в отличие от предыдущего способа в данном примере мы используем метод ReadXml объекта класса DataSet.

Единственная проблема, которая появилась после выполнения выше описанного кода, заключается в том, что теперь у нас появился не верный порядок столбцов.

заполненная таблица

Всё-таки хотелось бы, чтобы колонка id была первой. Исправить это достаточно просто, например можно воспользоваться свойством DisplayIndex.

dataGridView1.Columns["id"].DisplayIndex = 0;
dataGridView1.Columns["name"].DisplayIndex = 1;
dataGridView1.Columns["age"].DisplayIndex = 2;

Новый порядок столбцов: id, name, age.

На этом всё, если есть вопросы, то оставляйте их в комментариях.

Читайте также:

48 комментариев

  1. Как добавить данные в Datagridview понятно, а как обновлять его после добавления данных в XML?

  2. Если данные добавлены в xml файл, то тогда нужно просто заново выполнить чтение xml файла.

  3. Как я делал.

    public Form1()
    {
    InitializeComponent();
    ds.ReadXml(XmlPath);
    dataGridView1.DataSource = ds.Tables["Store"];
    }

    Данные в датагрид есть, потом через форму добавляю данные и делаю

    xDoc.Save(XmlPath);
    ds.ReadXml(XmlPath);

    У меня в датагрид данные не обновляются, а еще добавляются, причем первые строки без новой записи и еще эти же но уже с новой записью

  4. Как вариант попробовать отчистить DataSource, перед тем как добавить в него новые данные.

    InitializeComponent();
    ds.ReadXml(XmlPath);
    dataGridView1.DataSource = null; //Добавить
    dataGridView1.DataSource = ds.Tables["Store"];
  5. using System.Xml.Linq;
    Ошибка типа нет такого, перепробовал все сборки нет фамеворка.
    Вопрос, как сделать чтобы по нажатию на данную ячейку открывалась другая форма

  6. &#171;Ошибка типа нет такого&#187;? Нет кого или чего? Строки using System.Xml.Linq?
    В проект добавлена сборка System.Xml.Linq.dll?

    Открытие второй формы при клике по ячейке в DataGridView:

    private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
    {
    if (e.RowIndex != -1)
    {
    using (Form2 frm2 = new Form2())
    {
    frm2.ShowDialog();
    }
    }
    }

    Вопросы несвязанные с основной темой просьба задавать на форуме.

  7. Привет. Как к этому коду прикрутить счетчик при загрузке и/или прогресс бар?
    Помоги, а?
    В данный момент я использую этот код &#171;Если же Вам не хочется самостоятельно описывать логику работы с xml файлом&#187;
    Заранее спасибо. Надеюсь

  8. progressBar1.Minimum = 0;
    int nodeCount = xDoc.Descendants("friend").Count();
    progressBar1.Maximum = nodeCount;
    foreach (XElement elm in xDoc.Descendants("friend"))
    {
    progressBar1.Value += 1;
    }

    Во втором варианте не получится отследить, скорее всего, хотя возможно есть какое-то решение.

  9. а еще вопрос: проба 3. все теги без угловых скобок
    у меня примерно такая структура xml (теги picture имеют одинаковые названия внутри user)

    <users>
    <user>
    <picture>1.jpg</picture>
    <picture>2.jpg</picture
    <picture>3.jpg</picture>
    <picture>4.jpg</picture>
    </user>
    <user>
    тоже самое <picture></picture>
    </user>
    </users>

    Пытаюсь загружать в datagridview по твоему упрощенному методу
    &#171;Если же Вам не хочется самостоятельно описывать логику работы с xml файлом&#187;
    И эти теги не загружаются вообще(столбцов просто нет в DGV). Подскажи в чем дело и как исправить?

  10. Возможно, после чтения xml файла в ds.Tables было создано более 1-ой таблицы, поэтому нужно указать не ds.Tables[0], а ds.Tables[1] или ds.Tables[&#171;picture&#187;] тогда будет создана колонка и будет выведены все значения элементов picture.

  11. Забыл сказать что в xml до и после picture есть еще теги, и они выводятся в dgv, а picture не выводятся.
    Делал ds.Tables[«picture»] &#8212; да выводится колонка картинок, но только из первого тега picture, остальные игнорируются. (т.е. получается колонка в каждой ячейке по 1 картинке, а их у меня предположим по 3-5)
    Как же вывести все теги в dgv и все picture

  12. Забыл сказать что в xml до и после picture есть еще теги, и они выводятся в dgv, а picture не выводятся

    Я уже ответил на этот вопрос в предыдущем ответе.

    да выводится колонка картинок, но только из первого тега picture

    Приведённый ранее тобой xml код в DataSet преобразуется в таблицу &#171;picture&#187; с колонкой &#171;picture_Text&#187;, которая содержит все значения xml элемента &#171;picture&#187;, а не только первого тега &#171;picture&#187;.

    Поэтому:

    //выводит значения всех xml элементов "picture"
    dgv.DataSet = ds.Tables["picture"];
  13. Да. точно все работает, просто думал что картинки от одного тега user будут в 1 ячейке dgv, а они каждая в отдельной.
    А при обработке строк в dgv (если какие-то теги автоматом не показываются в dgv) информация полностью будет обрабатываться или только то, что загрузилось в dgv? ну как пример: вот не загрузились картинки из этих тегов в dgv, если обработать строки, то теги картинок останутся или исчезнут?

  14. Строки, которые содержат xml теги хранятся в DataTable, а в dgv они лишь только выводятся для отображения. Поэтому, если изменения происходят только в dgv, то на DataTable &#8212; это никак не влияет.

  15. Не все понял, А если не все теги загрузились из xml в dgv (предположим что не загрузились в dgv теги picture), далее мы выделили строки в dgv и скопировали (или вырезали) их и вставили в другой xml &#8212; все теги из первого xml перейдут во второй или только видимые?

  16. А если не все теги загрузились из xml в dgv

    Почему не загрузились? Возникла ошибка или что-то иное? Добавляйте конкретные примеры с кодом, тогда будут ответы.

    мы выделили строки в dgv и скопировали (или вырезали) их и вставили в другой xml

    Каким образом реализуются эти операции? Где код?

    все теги из первого xml перейдут во второй или только видимые

    Рекомендую почитать про взаимосвязь таблиц в ADO.NET

  17. Здравствуйте. Пытаюсь вашим способом получить информацию о книге из fb2 и ничего не выводит, никаких ошибок нет. Информацию о книге не всю, а просто у потомка author вывести first-name.

  18. Привет. Как выглядит этот xml файл (та часть, которую нужно считать и вывести)?

  19. <?xml version=&#034;1.0&#034; encoding=&#034;windows-1251&#034;?>
    <FictionBook xmlns=&#034;h_t_t_p://w_w_w.название сайта/xml/fictionbook/2.0&#034; xmlns:l=&#034;h_t_t_p://w_w_w.название сайта/1999/xlink">
    <description>
    <title-info>
    <genre>sci_history</genre>
    <author>
    <first-name>Бернард</first-name>
    <last-name>Корнуэлл</last-name>
    </author>

  20. Например, так:

    //читаем xml файл
    DataSet ds = new DataSet();
    ds.ReadXml(@"имя_файла.xml");
    //создаём колонку "author_name" в dgv
    dataGridView1.Columns.Add("author_name", "имя автора");
    //выводим имя автора
    dataGridView1.Rows[0].Cells[0].Value = ds.Tables["author"].Rows[0]["first-name"];
  21. Спасибо, я попытался вывести еще genre
    dataGridView1.Rows[0].Cells[0].Value = ds.Tables[&#171;title-info&#187;].Rows[0][&#171;genre&#187;];
    Тогда выводит жанр но не выводит имя, просто пустое поле.

  22. //создаём колонку "author_name" в dgv
    dataGridView1.Columns.Add("author_name", "имя автора");
    //создаём колонку "genre" в dgv
    dataGridView1.Columns.Add("genre", "жанр");
    //выводим имя автора
    dataGridView1.Rows[0].Cells[0].Value = ds.Tables["author"].Rows[0]["first-name"];
    //выводим жанр
    dataGridView1.Rows[0].Cells[1].Value = ds.Tables["title-info"].Rows[0]["genre"];
  23. Не подскажите как отбрасывать не нужную часть читаемого xml файла, я знаю что вся информация которая мне нужно содержится в потомках и потомках потомков , а все что после нужно отбросить и забыть.

  24. Не совсем понял вопрос. В DataSet создаются несколько таблиц: ds.Tables[&#171;author&#187;], ds.Tables[&#171;title-info&#187;] и т.д. для каждого xml элемента.

    Например, ds.Tables[&#171;author&#187;] содержит только определённую часть:

    <author>
    <first-name>Бернард</first-name>
    <last-name>Корнуэлл</last-name>
    </author>
  25. Да так, просто когда я пытаюсь по этому шаблону достать данные из другой книги,в ней все примерно так же пишет:
    Необработанное исключение типа &#171;System.Data.DuplicateNameException&#187; в System.Data.dll
    Дополнительные сведения: Не удалось добавить столбец с именем &#171;p&#187;: вложенная таблица с таким именем уже принадлежит этому DataTable.
    Исключение вызывается, если при операции с объектом, относящимся к DataSet, нарушается уникальность имен объектов базы данных.
    А если скопировать в новый xml файл только ту часть книги которая мне нужна все выводиться, поэтому интересно нельзя ли запретить проверять весь файл?

  26. Проверку отключать не стоит, даже если это возможно сделать. А ошибка в каком месте кода возникает?

  27. ошибка в ds.ReadXml(@&#187;D:/an.fb2&#8243;);

    Проблема в том что из одной книги этот код читает данные и выводит,а из другой ошибка.

  28. Внешне никакого. Есть все те же поля, просто много других и все. А мне нужно шаблон сделать что б из любой книги бралась одна и та же информация, при условии что в каждой книге она будет. В той другой она есть.

  29. c# код не изменялся? Попробовал, создал несколько xml файлов с одинаковой структурой и все загрузились без ошибок. Как выглядит код метода, который используется для чтения xml файла?

  30. Код не менял. Изначальный файл который он читал он и читает. Если из книги которая не читается скопировать в другой файл только нужную мне часть, в каждой книге она начинается с title-info и ей же заканчивается то выводит все без ошибок. Я поэтому и спрашивал как искать только в title-info и не идти дальше по всей книге. Код тот же что вы давали выше:

    DataSet ds = new DataSet();
    ds.ReadXml(@"D:/book.fd2");
    dataGridView1.Columns.Add("book-title", "название");
    dataGridView1.Rows[0].Cells[0].Value = ds.Tables["title-info"].Rows[0]["book-title"];

    Ну и таких дгр на каждый элемент который мне нужен.

  31. Я поэтому и спрашивал как искать только в title-info и не идти дальше по всей книге

    Метод ReadXml считывает весь xml файл целиком, поэтому прочитать отдельную часть не получится.

    Не понятно, почему возникает ошибка, потому что я попробовал изменить структуру всех xml файлов и все отлично работает. Как выглядит весь c# код? Потому что, скорее всего, ошибка в нём.

  32. вот весь код который есть

    //читаем xml файл
    DataSet ds = new DataSet();
    ds.ReadXml(@"D:/gip.txt");
    //создаём колонки в dgv
    dataGridView1.Columns.Add("book-title", "название");
    dataGridView1.Columns.Add("author_name", "имя автора");
    dataGridView1.Columns.Add("last-name", "имя автора");
    dataGridView1.Columns.Add("genre", "жанр");
    //dataGridView1.Columns.Add("annotation", "жанр");
    //выводим имя автора
    dataGridView1.Rows[0].Cells[0].Value = ds.Tables["title-info"].Rows[0]["book-title"];
    dataGridView1.Rows[0].Cells[1].Value = ds.Tables["author"].Rows[0]["first-name"];
    dataGridView1.Rows[0].Cells[2].Value = ds.Tables["author"].Rows[0]["last-name"];
    dataGridView1.Rows[0].Cells[3].Value = ds.Tables["title-info"].Rows[0]["genre"];
  33. Точно также всё работает, ошибок не возникает. Попробуй по другому тогда сделать, например:

    //создаём таблицу с двумя колонками
    DataTable dt = new DataTable("books");
    dt.Columns.Add("genre", typeof(String));
    dt.Columns.Add("author_name", typeof(String));
    DataRow newRow = null;
    //загружаем xml
    XDocument xDoc = XDocument.Load("путь к файлу.xml");
    //значение из атрибута FictionBook xmlns
    XNamespace xNamespace = "h_t_t_p://w_w_w.название_сайта.ru/xml/fictionbook/2.0";
    //получаем элемент title-info
    var titles_info = xDoc.Descendants(xNamespace + "title-info");
    foreach (XElement title_info in titles_info)
    {
    //создаём новую строку
    newRow = dt.NewRow();
    newRow["genre"] = ((XElement)title_info.FirstNode).Value;
    newRow["author_name"] = ((XElement)title_info.Element(xNamespace + "author").FirstNode).Value;
    //добавляем строку в таблицу
    dt.Rows.Add(newRow);
    }
    dataGridView1.DataSource = dt;
  34. Да, так выводит из всех книг.

    newRow["genre"] = ((XElement)title_info.FirstNode).Value;
    newRow["author_name"] = ((XElement)title_info.Element(xNamespace + "author").FirstNode).Value;

    Можете подробнее про это рассказать?

    Уточню как вывести второе значение в текущей ноде, в данном случае lastname

  35. newRow[«genre»] = ((XElement)title_info.FirstNode).Value;

    У элемента title_info получаем значение первого дочернего узла &#171;genre&#187;.

    newRow[«author_name»] = ((XElement)title_info.Element(xNamespace + «author»).FirstNode).Value;

    У элемента title_info сначала находим элемент &#171;author&#187;, после чего получаем значение первого дочернего узла &#171;first-name&#187;.

    примеры

    Получить значение элемента lastname:

    newRow["author_lastname"] = ((XElement)title_info.Element(xNamespace + "author").LastNode).Value;
  36. Здравствуйте почему то читает только первые совпадения и все(

    1
    Работа
    turtuty
    7 декабря 2015 г.
    Важно
    Не выполняется

    2
    Работа
    turtuty
    7 декабря 2015 г.
    Важно
    Не выполняется

    4
    Повседневное
    ПОВСДНЕВНОЕ
    8 декабря 2015 г.
    Важно
    Готово

    8
    Работа
    turtuty
    7 декабря 2015 г.
    Важно
    Не выполняется

    Вот код

    public partial class Form1 : Form
    {
    public DataSet NewDataSet = new DataSet();
    string filePath = "C:/Users...../WindowsFormsApplication3/XMLFile1.xml";
    private string sCurDir = string.Empty;
    public Form1()
    {
    InitializeComponent();
    dataGridView1.Columns.Add("text", "Задача");
    dataGridView1.Columns.Add("data", "Дата");
    dataGridView1.Columns.Add("importance", "Важность");
    dataGridView1.Columns.Add("state", "Статус");
    dataGridView2.Columns.Add("text", "Задача");
    dataGridView2.Columns.Add("data", "Дата");
    dataGridView2.Columns.Add("importance", "Важность");
    dataGridView2.Columns.Add("state", "Статус");
    dataGridView3.Columns.Add("text", "Задача");
    dataGridView3.Columns.Add("data", "Дата");
    dataGridView3.Columns.Add("importance", "Важность");
    dataGridView3.Columns.Add("state", "Статус");
    }
    private void Form1_Load(object sender, EventArgs e)
    {
    NewDataSet.ReadXml(filePath, XmlReadMode.Auto);
    dataGridView1.Rows[0].Cells[0].Value = NewDataSet.Tables["job"].Rows[0]["text"];
    dataGridView1.Rows[0].Cells[1].Value = NewDataSet.Tables["job"].Rows[0]["data"];
    dataGridView1.Rows[0].Cells[2].Value = NewDataSet.Tables["job"].Rows[0]["importance"];
    dataGridView1.Rows[0].Cells[3].Value = NewDataSet.Tables["job"].Rows[0]["state"];
    dataGridView2.Rows[0].Cells[0].Value = NewDataSet.Tables["everyday"].Rows[0]["text"];
    dataGridView2.Rows[0].Cells[1].Value = NewDataSet.Tables["everyday"].Rows[0]["data"];
    dataGridView2.Rows[0].Cells[2].Value = NewDataSet.Tables["everyday"].Rows[0]["importance"];
    dataGridView2.Rows[0].Cells[3].Value = NewDataSet.Tables["everyday"].Rows[0]["state"];
    dataGridView3.Rows[0].Cells[0].Value = NewDataSet.Tables["private"].Rows[0]["text"];
    dataGridView3.Rows[0].Cells[1].Value = NewDataSet.Tables["private"].Rows[0]["data"];
    dataGridView3.Rows[0].Cells[2].Value = NewDataSet.Tables["private"].Rows[0]["importance"];
    dataGridView3.Rows[0].Cells[3].Value = NewDataSet.Tables["private"].Rows[0]["state"];
    }
    }
    }

    В чем моя ошибка?

  37. <?xml version=&#034;1.0&#034; encoding=&#034;windows-1251&#034; standalone=&#034;yes&#034;?>
    <NewDataSet>
    <job>
    <id>1</id>
    <category>Работа</category>
    <text>задача1</text>
    <data>7 мая 2015 г.</data>
    <importance>?????</importance>
    <state>?? ???????????</state>
    </job>
    <everyday>
    <id>2</id>
    <category>Повседневное</category>
    <text>Задача</text>
    <data>7 мая 2015 г.</data>
    <importance>Важно</importance>
    <state>Выполняется</state>
    </everyday>
    <everyday>
    <id>3</id>
    <category>Повседневное</category>
    <text>Задача</text>
    <data>7 мая 2015 г.</data>
    <importance>Важно</importance>
    <state>Выполняется</state>
    </everyday>
    <private>
    <id>4</id>
    <category>Личное</category>
    <text>Задача</text>
    <data>7 мая 2015 г.</data>
    <importance>Важно</importance>
    <state>Выполняется</state>
    </private>
    </NewDataSet>
  38. почему то читает только первые совпадения и все

    Потому что не изменяется индекс строки.

    //выводит первую строку
    dataGridView2.Rows[0].Cells[0].Value = NewDataSet.Tables["everyday"].Rows[0]["text"];
    //выводит вторую строку
    dataGridView2.Rows[1].Cells[0].Value = NewDataSet.Tables["everyday"].Rows[1]["text"];

    А можно сократить код, например:

    DataSet NewDataSet = new DataSet();
    NewDataSet.ReadXml(@"путь к xml файлу");
    dataGridView1.DataSource = NewDataSet.Tables["job"];
    dataGridView2.DataSource = NewDataSet.Tables["everyday"];
    //dataGridView3.DataSource = NewDataSet.Tables["private"];
  39. Привет. Не знаю где спросить. Спрошу тут:
    Загрузил и вывел XML в datagrid по упрощенному методу. так:
    DataSet ds = new DataSet(&#171;Friends&#187;);
    ds.ReadXml(@&#187;..//..//имя файла.xml&#187;);
    dataGridView1.DataSource = ds.Tables[friend];
    &#8212;&#8212;&#8212;-
    И есть файл со значениями по одному в каждой строке так:
    111111
    22222222
    33333333
    444444444
    В данный момент файл txt, но не принципиально, если надо засуну в xml и оберну каждое значение в любой xml-тег.
    Как бы организовать поиск этих значений по одному в определенном теге исходного xmlя и если найдено, то заменять на одно значение ну например 000000. Догадываюсь, что предварительная загрузка в datagrid может быть лишней, а сразу брать из второго и искать и заменять в первом.
    Подмогните а? т.е. тысячи разных значений заменить на 000000

  40. Привет.

    Если я правильно понял, то вот пример и решение:

    //дано:
    <cars>
    <car><speed>210</speed></car>
    <car><speed>210</speed></car>
    <car><speed>210</speed></car>
    <car><speed>220</speed></car>
    </cars>

    Хотим заменить все значения 210 на 11111.

    int replace_value = 11111;
    //using System.Xml.Linq;
    XDocument xDoc = XDocument.Load("cars.xml");
    var elmsSpeed = xDoc.Descendants("speed");
    foreach (XElement elmSpeed in elmsSpeed)
    {
    if (elmSpeed.Value.Contains("210"))
    {
    elmSpeed.Value = replace_value.ToString();
    }
    }
    xDoc.Save(@"cars.xml");

    А чтение файла и перебор остальных значений в цикле, думаю, не составит трудностей.

    Можно обернуть всё в метод:

    private void ReplaceNodeValue(int original_value, int replace_value)
    {
    //код выше
    }
  41. Почему то добавляется в конце одна пустая строка и она помечена &#171;*&#187;. Все делал как показано у вас в примере. И еще как можно убрать левый пустой столбец, где находится стрелка?

  42. Как добавить запись также из xml файла туда где стоит стрелочка?

    Стрелочка просто указывает, что выбрана данная строка, то есть

    DataGridViewRow curRow = dataGridView1.CurrentRow;

    У строки есть ячейки (свойство Cells),

    dgv.CurrentRow.Cells["name"].Value = "какое-то значение из xml файла";
    dgv.CurrentRow.Cells["age"].Value = "какое-то значение из xml файла";
    ....

    Почему то добавляется в конце одна пустая строка и она помечена «*».

    Если выбрать control dataGridView (в режиме разработки), то справа вверху появится маленький квадрат со стрелкой. Нужно нажать на него и убрать первую галочку рядом с надписью &#171;Enable Adding&#187;.

Добавить комментарий для admin Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *