Стек страничного интерфейса WPF UserControl

154
18 апреля 2022, 03:10

Вот что мне хочется реализовать (подобное), только для кнопки "назад", где вместо ссылок на сайт - ссылки на UserControl. Желательно ещё и с выходными параметрами. https://itchief.ru/lessons/javascript/javascript-history-object#:~:text=%D0%9F%D1%80%D0%B8%20%D0%BD%D0%B0%D0%B6%D0%B0%D1%82%D0%B8%D0%B8%20%D0%BD%D0%B0%20%D0%BA%D0%BD%D0%BE%D0%BF%D0%BA%D1%83%20%22%D0%9D%D0%B0%D0%B7%D0%B0%D0%B4,%D0%B2%D0%BD%D1%83%D1%82%D1%80%D0%B8%20%D1%8D%D1%82%D0%BE%D0%B3%D0%BE%20%D0%BE%D0%BA%D0%BD%D0%B0%20(%D0%B2%D0%BA%D0%BB%D0%B0%D0%B4%D0%BA%D0%B8)

Ломаю голову который день и не могу придумать, как правильнее организовать стек для страничного интерфейса. Но мне хочется сделать так, чтобы к ContentPresenter с помощью Binding можно было привязать свойство, которое реализует INPC и стек, в котором хранятся ТИПЫ предыдущих UserControl-ов, а не их объектов, т.к. иначе список экземпляров будет засорять ОЗУ. И при "открытии" нового UC добавлять в стек его тип данных, а при закрытии удалять последний тип из стека и присваивать главному свойству созданный новый экземпляр с предыдущим типом данных в стеке (типо "return new SomeType"). Возможно ли сделать такой стек? Думаю, что такое возможно с помощью делегатов, но для этого на каждой ViewModel я должна прописывать одну и ту же логику. Хотелось бы всё это автоматизировать, если такое вообще возможно. Слышала про тип данных Type, но как создать новый объект с его помощью - не знаю.

//// Может стоит создать класс, в котором будет описан и метод, и стек с типами данных? Осталось только понять, как возвращать или создавать новый объект с типом данных, полученного из стека. Что-то по типу этого... Не знаю.

class StackUC:INPC
{
private UserControl Uc;
public UserControl UC {get{return Uc;} set{Uc = value; OnPropertyChanged();}}
private Stack<Type> Stc = new Stack<Type>;
public Open(Type T)
{
UC = new T;
Stc.Add(T);
}
public Close()
{
Stc.Pop()
UC = new Stc.Peek();
}
}

//// Ещё появилась идея создать родительский класс, от которого будут наследоваться методы "открытия" и "закрытия" UC.

Answer 1

Я смогла наконец реализовать это.

Для реализации такой возможности я создала класс HistoryInterface, содержащий основную логику, и дополнительный HistoryUC, который является представлением записи для стека (хранит информацию, необходимую для создания UserControl-a).

Далее код с комментариями:

public static class HistoryInterface
{
    static object mframe;//Объект, который хранит нужный UserControl
    public static object Mframe { get { return mframe; } set { mframe = value; NotifyStaticPropertyChanged(); } }//Свойство, 
                                                                            //которое хранит и отображает текущий UserControl
    static Stack<HistoryUC> History = new Stack<HistoryUC>();//Стек истории UserControl-ов
    public static void AddUC(object frame, object[] param = null)//Метод добавления UC в History. Выполняется в конструкторе необходимого UC
    {
        Mframe = frame;//Изменение отображаемого UC
        History.Push(new HistoryUC(frame.GetType(), param));//Добавление "конфигурации" объекта в стек
    }
    public static void DropUC()//Метод "закрытия" UC. Может выполняться, например, при нажатии кнопки "назад"
    {
        History.Pop();//Удаляем последний объект
        HistoryUC obj = History.Peek();//Выбираем последнюю "конфигурацию" объекта
        Mframe = obj.ret();//Выполняем создание UC
    }
    //Реализация INPC для статических свойств в статическом классе
    public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
    private static void NotifyStaticPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (StaticPropertyChanged != null)
        {
            StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class HistoryUC //Класс, который описывает элемент стека History.
                       //Хранит тип данных и параметры, необходимые для создания экземпляра указанного типа
{
    Type type;
    object[] args;//Переменная, которая хранит необходимые аргументы
    public HistoryUC(Type uc, object[] arg)//конструктор нового экземпляра
    {
        args = arg;//Присваиваем входные аргументы
        type = uc;//Присваиваем тип данных
    }
    public object ret()//Метод, который возвращает новый экземпляр UC
    {
        return Activator.CreateInstance(type, args);
    }
}

Теперь, в конструкторах UserControl-ов, которые необходимо запоминать в стек, нужно прописывать метод HistoryInterface.AddUC() (причём, если параметров нет, их можно не указывать). И, таким образом, при создании нового экземпляра UserControl-a будет создаваться запись в стек. А при закрытии текущего userControl-a, на кнопку выхода нужно создать обработчик (или команду), в которой прописывается метод HistoryInterface.DropUC()

Свойство MFrame хранит текущий UserControl и привязан к ContentPresenter, который находится в окне. Т.к. это свойство изменяемое, пришлось реализовать а-ля интерфейс INotifyPropertyChanged для статического класса.

READ ALSO
Как разделить List во View

Как разделить List во View

Использую ChartJS для отрисовки диаграммыВ принимаемых значениях lables и data может обрабатываться только разделенные значения

359
Rider. Пустой .cs файл при генерации из web-reference

Rider. Пустой .cs файл при генерации из web-reference

Когда я добавляю web-reference к https://wwwonvif

131
Почему массив выдает такой результат? С#

Почему массив выдает такой результат? С#

Результат должен быть просто 1,но почему то результат 2,1,2Метод ArrayDiff должен из массива a удалять все такие же цифры, которые есть в массиве...

110