Динамические классы, обработка событий и создание меток Текст Adventure C# WPF

В настоящее время я делаю текстовую игру, которая основана на комнатах. Я довольно неопытен в C#, поэтому для любых решений, скорее всего, понадобятся примеры или источники. Тем не менее, моя проблема в том, что каждый раз, когда я создаю новую "комнату", мне нужно переделать много работы, и я хочу знать, как я могу создать класс комнаты, чтобы делать то, что я хочу.

Таким образом, в основном, каждый раз, когда я создаю комнату, я делаю одно и то же: 1. Инициализирую некоторый прогон, содержащий мой текст. 2. Инициализируйте некоторые интерактивные ярлыки, которые представляют мои навигационные события. 3. Инициализируйте указанные события, соответствующие метке.

Все это отнимает много времени, каждый раз, когда мне приходится все переделывать, это может привести к ошибкам.

Это сделано в C# WPF с использованием FlowDocument, так как это текстовая приключенческая игра

Вот мой код:

{
    public MainWindow()
    {
        InitializeComponent();
        StartingArea();
        myFlowDocument.Blocks.Add(myParagraph);
    }
    Paragraph myParagraph = new Paragraph();
    Paragraph myParagraph2 = new Paragraph();
    public void StartingArea()
    {

        InlineLabel lStartingAreaLook = new InlineLabel("look.");
        lStartingAreaLook.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaLook_Click);
        ModInlineUIContainer lStartingArea_Look = new ModInlineUIContainer(lStartingAreaLook);

        object[] pStartingRoom = { tStartingText, lStartingArea_Look };
        AddInline(pStartingRoom);
        this.Content = myFlowDocument;
        void ClearParagraph()
        {
            foreach (Inline run in myParagraph.Inlines.ToList())
            {
                myParagraph.Inlines.Remove(run);
            }
        }
        void lStartingAreaLook_Click(object sender, MouseButtonEventArgs e)
        {
            ClearParagraph();
            StartingAreaLook();
        }
        void StartingAreaLook()
        {

            InlineLabel lStartingAreaLook_Speak = new InlineLabel("speak");
            lStartingAreaLook_Speak.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaLook_Speak_Click);
            ModInlineUIContainer cStartingAreaSpeak = new ModInlineUIContainer(lStartingAreaLook_Speak);

            InlineLabel lStartingArea_Use = new InlineLabel("use");
            lStartingArea_Use.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaLook_Use_Click);
            ModInlineUIContainer cStartingAreaUse = new ModInlineUIContainer(lStartingArea_Use);

            object[] pStartingArea2 = { tStartingAreaLook, cStartingAreaSpeak, tStartingAreaLook2, cStartingAreaUse, tStartingAreaLook3 };
            AddInline(pStartingArea2);
            void lStartingAreaLook_Speak_Click(object sender, MouseButtonEventArgs e)
            {
                ClearParagraph();
                StartingAreaSpeak();
                //myParagraph.Inlines.Add(tStartingAreaLook);
            }
            void lStartingAreaLook_Use_Click(object sender, MouseButtonEventArgs e)
            {
                ClearParagraph();
                StartingAreaUse();
                //myParagraph.Inlines.Add(tStartingAreaLook);
            }
            void StartingAreaSpeak()
            {

                InlineLabel lStartingAreaSpeak_Look = new InlineLabel("look");
                lStartingAreaSpeak_Look.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaSpeak_Look_Click);
                ModInlineUIContainer cStartingAreaSpeak_Look = new ModInlineUIContainer(lStartingAreaSpeak_Look);

                InlineLabel lStartingAreaSpeak_Use = new InlineLabel("use");
                lStartingAreaSpeak_Use.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaSpeak_Use_Click);
                ModInlineUIContainer cStartingAreaSpeak_Use = new ModInlineUIContainer(lStartingAreaSpeak_Use);

                object[] pStartingAreaSpeak = { tStartingAreaSpeak, cStartingAreaSpeak_Look, tStartingAreaSpeak2, cStartingAreaSpeak_Use, tStartingAreaSpeak3 };
                AddInline(pStartingAreaSpeak);
                void lStartingAreaSpeak_Look_Click(object sender, MouseButtonEventArgs e)
                {
                    ClearParagraph();
                    StartingAreaLook();
                    //myParagraph.Inlines.Add(tStartingAreaLook);
                }
                void lStartingAreaSpeak_Use_Click(object sender, MouseButtonEventArgs e)
                {
                    ClearParagraph();
                    StartingAreaUse();
                    //myParagraph.Inlines.Add(tStartingAreaLook);
                }
            }
            void StartingAreaUse()
            {

                Run tStartingArea_Use = new Run($@"{sUse}");

                InlineLabel lStartingArea_Use_Restart = new InlineLabel("Restart");
                lStartingArea_Use_Restart.MouseDoubleClick += new MouseButtonEventHandler(lStartingArea_Use_Restart_Click);
                ModInlineUIContainer cStartingArea_Use_Restart = new ModInlineUIContainer(lStartingArea_Use_Restart);

                object[] pStartingAreaUse = { tStartingArea_Use, cStartingArea_Use_Restart };

                AddInline(pStartingAreaUse);


                void lStartingArea_Use_Restart_Click(object sender, MouseButtonEventArgs e)
                {
                    ClearParagraph();
                    StartingArea();
                    //myParagraph.Inlines.Add(tStartingAreaLook);
                }
            }
        }
    }
    private void RemoveDoubleClickEvent(Label b)
    {
        FieldInfo f1 = typeof(Control).GetField("EventDoubleClick",
            BindingFlags.Static | BindingFlags.NonPublic);
        object obj = f1.GetValue(b);
        PropertyInfo pi = b.GetType().GetProperty("Events",
            BindingFlags.NonPublic | BindingFlags.Instance);
        EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
        list.RemoveHandler(obj, list[obj]);
    }
    public void AddInline(object[] inline)
    {
        foreach(dynamic element in inline)
        {
            myParagraph.Inlines.Add(element);
        }
    }
    public void RemoveInline(object[] inline)
    {
        foreach (dynamic element in inline)
        {
            myParagraph.Inlines.Add(element);
        }
    }
}

Теперь я хотел бы создать класс, который я могу использовать каждый раз, когда создаю новую комнату. Проблема в том, что мне нужно создавать события и неизвестное количество меток для каждого из них.

Я бы хотел сделать что-то похожее на это:

{
Public void Livingroom()
{

    Room Livingroom = new Room();
    SetupRoom(Room.Livingroom, 3, 2);
    //Whereas the first is the room object, the second is the amount of Run, the third is the amount of labels
    object[] LivingroomParagraph = { Livingroom.Run1, Livingroom.Run2, Livingroom.Label1, Livingroom.Run3, Livingroom.Label2 };
    AddInline(LivingroomParagraph);
    void lLivingroom1(object sender, MouseButtonEventArgs e)
    {
        //Do something
    }

    void lLivingroom2(object sender, MouseButtonEventArgs e)
    {
        //Do something

    }

}

}

В общем, мне нужен конструктор, который будет генерировать динамически, особенно те части:

Run tStartingArea_Use = new Run($@"{sUse}");

                InlineLabel lStartingArea_Use_Restart = new InlineLabel("Restart");
                lStartingArea_Use_Restart.MouseDoubleClick += new MouseButtonEventHandler(lStartingArea_Use_Restart_Click);
                ModInlineUIContainer cStartingArea_Use_Restart = new ModInlineUIContainer(lStartingArea_Use_Restart);

Это довольно сложно, поэтому я надеюсь, что я получу некоторую помощь!

1 ответ

Решение

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

Главное, что вы повторяете, это создание вашего ModInlineUIContainer объект. Я бы посоветовал вам сделать метод, который сделает за вас тяжелую работу:

private ModInlineUIContainer CreateContainer(string text, Action mouseDoubleClick)
{
    var label = new InlineLabel(text);
    var container = new ModInlineUIContainer(label);

    label.MouseDoubleClick += (s, e) => mouseDoubleClick();

    return container;
}

.MouseDoubleClick += (s, e) => синтаксис устраняет необходимость создания отдельного метода и использования Action mouseDoubleClick давайте перейдем к любому действию, которое вы хотите выполнить, когда MouseDoubleClick Поднялся.

Еще один рефакторинг я сделал, чтобы удалить ClearParagraph(); вызов метода из каждого обработчика события и просто положить его в начало каждого StartingArea*() метод.

Это означает, что я могу заменить этот код:

InlineLabel lStartingAreaLook_Speak = new InlineLabel("speak");
lStartingAreaLook_Speak.MouseDoubleClick += new MouseButtonEventHandler(lStartingAreaLook_Speak_Click);
ModInlineUIContainer cStartingAreaSpeak = new ModInlineUIContainer(lStartingAreaLook_Speak);

void lStartingAreaLook_Speak_Click(object sender, MouseButtonEventArgs e)
{
    ClearParagraph();
    StartingAreaSpeak();
}

...с этим:

    ModInlineUIContainer speak = CreateContainer("speak", () => StartingAreaSpeak());

Затем я изменил AddInLine параметр метода, чтобы иметь подпись params object[] inline чтобы я мог вызывать его напрямую, не создавая сначала массив.

Теперь остальная часть кода вываливается красиво. Это выглядит так:

    public MainWindow()
    {
        InitializeComponent();
        StartingArea();
        myFlowDocument.Blocks.Add(myParagraph);
        this.Content = myFlowDocument;
    }

    Paragraph myParagraph = new Paragraph();

    private ModInlineUIContainer CreateContainer(string text, Action mouseDoubleClick)
    {
        var label = new InlineLabel(text);
        var container = new ModInlineUIContainer(label);

        label.MouseDoubleClick += (s, e) => mouseDoubleClick();

        return container;
    }

    public void StartingArea()
    {
        ClearParagraph();
        var look = CreateContainer("look", () => StartingAreaLook());
        AddInline(tStartingText, look);
    }

    void StartingAreaLook()
    {
        ClearParagraph();
        var speak = CreateContainer("speak", () => StartingAreaSpeak());
        var use = CreateContainer("use", () => StartingAreaUse());
        AddInline(tStartingAreaLook, speak, tStartingAreaLook2, use, tStartingAreaLook3);
    }

    void StartingAreaSpeak()
    {
        ClearParagraph();
        var look = CreateContainer("look", () => StartingAreaLook());
        var use = CreateContainer("use", () => StartingAreaUse());
        AddInline(tStartingAreaSpeak, look, tStartingAreaSpeak2, use, tStartingAreaSpeak3);
    }

    void StartingAreaUse()
    {
        ClearParagraph();
        var tStartingArea_Use = new Run($"{sUse}");
        var restart = CreateContainer("Restart", () => StartingArea());
        AddInline(tStartingArea_Use, restart);
    }

    void ClearParagraph()
    {
        foreach (Inline run in myParagraph.Inlines.ToList())
        {
            myParagraph.Inlines.Remove(run);
        }
    }

    public void AddInline(params object[] inline)
    {
        foreach (dynamic element in inline)
        {
            myParagraph.Inlines.Add(element);
        }
    }

Это должно быть намного меньше повторения кода.


Если вы хотите получить всю забавную обезьяну, то вы можете попробовать это:

public MainWindow()
{
    InitializeComponent();

    myFlowDocument.Blocks.Add(myParagraph);
    this.Content = myFlowDocument;

    _areas = new Dictionary<string, Func<object[]>>()
    {
        { "start", () => new object[] { CreateContainer("look") } },
        { "look", () => new object[] { tStartingAreaLook, CreateContainer("speak"), tStartingAreaLook2, CreateContainer("use"), tStartingAreaLook3 } },
        { "speak", () => new object[] { tStartingAreaLook, CreateContainer("look"), tStartingAreaLook2, CreateContainer("use"), tStartingAreaLook3 } },
        { "use", () => new object[] { new Run($"{sUse}"), CreateContainer("start") } },
    };

    Starting("start");
}

private void Starting(string key)
{
    foreach (Inline run in myParagraph.Inlines.ToList())
    {
        myParagraph.Inlines.Remove(run);
    }
    foreach (dynamic element in _areas["look"]())
    {
        myParagraph.Inlines.Add(element);
    }
}

Paragraph myParagraph = new Paragraph();

Dictionary<string, Func<object[]>> _areas;

private ModInlineUIContainer CreateContainer(string text)
{
    var label = new InlineLabel(text);
    var container = new ModInlineUIContainer(label);

    label.MouseDoubleClick += (s, e) => Starting(text);

    return container;
}
Другие вопросы по тегам