动态 类 处理事件和标签创建文本冒险 C# WPF
Dynamic Classes Handling Events and Label Creation Text Adventure C# WPF
我目前正在做一个基于房间的文字游戏。我在 C# 方面相当缺乏经验,因此任何解决方案很可能都需要一些示例或一些资源来提供帮助。
话虽这么说,我的问题是每次我创建一个新的 "room" 时,我都需要重做很多工作,我想知道如何创建一个房间 class 来做我想做的事。
所以基本上,每次我创建一个房间时,我都会这样做:
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);
}
}
}
现在我想做的是创建一个 class,我可以在每次创建新房间时使用它。问题是我需要为每个事件创建事件和未知数量的标签。
我基本上希望能够做类似这样的事情:
{
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);
这个比较复杂,希望能得到一些帮助!
我认为您不需要费心创建 class 来简化此过程。您实际上只是在重复大量代码,您可以将它们很好地包装到一个函数中。
您要重复的关键是 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;
}
我目前正在做一个基于房间的文字游戏。我在 C# 方面相当缺乏经验,因此任何解决方案很可能都需要一些示例或一些资源来提供帮助。 话虽这么说,我的问题是每次我创建一个新的 "room" 时,我都需要重做很多工作,我想知道如何创建一个房间 class 来做我想做的事。
所以基本上,每次我创建一个房间时,我都会这样做: 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);
}
}
}
现在我想做的是创建一个 class,我可以在每次创建新房间时使用它。问题是我需要为每个事件创建事件和未知数量的标签。
我基本上希望能够做类似这样的事情:
{
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);
这个比较复杂,希望能得到一些帮助!
我认为您不需要费心创建 class 来简化此过程。您实际上只是在重复大量代码,您可以将它们很好地包装到一个函数中。
您要重复的关键是 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;
}