 Welcome to the Network Engineering video blog. I am your host, Michael Crane. In today's video, we will implement FileSave and SaveAs to write our nodes and links configurations to a text file. This will allow us to load nodes, links, and their layout when we first start Mogwai instead of having to provision everything from scratch. A real time saver. We will be using WPFS XAML menu tag to add menu items, FileOpen, FileSave, and FileSaveAs commands. We will also be using Win32 save file dialog for the user interface and using the stream writer to write our text files. So let's get started. Like I was saying, we want to be able that we want to save our routers and we want to save the links and we also want to save the location of these guys, right? So if we have a big, you know, configuration like with 20 routers and bunch of switches and that sort of thing, we want to be able to just do a FileOpen and pull that configuration in. Otherwise, we'd be repositioning this constantly. So in this video, I only implemented FileSave and FileSaveAs. Let me just show you what I did. I wanted to make this video kind of short anyway, because the Open config is probably going to be a lot more interesting. So let me pull up a diff here. Okay, so in the main window, the only thing I added in the canvas was this menu. Okay, so I just added the menu items for Open, Save, and SaveAs. And for some reason, I noticed it's not putting the, when you do the underscore open, it's supposed to, when you hit Alternate, Alt O, it should put that on there, but it's not working. So I'll have to, we'll have to visit that later. Okay, so anyway, we have these, these menu items I added, which is pretty simple stuff. Now we'll go look at, oh, and then the globals. Let's look at him real quick. I added the default directory, which is just in my documents slash Mogwai. All right. And then the default file filter, which is, I'm just making the config files, text files right now. Nothing fancy. And the config file is just being initialized as null. And the default config Y is just Mogwai. Our Mogwai config.txt, right? And these are just global variables, so anyone can access them and, and read them if they need to. So let's see, here's where most of the stuff happened. We'll start from the top. I had to import system IO for this, our new constructor, right? So this main window didn't have a constructor to begin with. So I went ahead and added it. And I added it because if there's, I wanted to make sure if there wasn't a default directory in the my documents area, then we're going to create one. All right. That's what that, this does right here. Then the, the open file right here, I, there is a subroutine for it. But like I said, it's not, I just copied this config out of the example. So, and kind of modified it a little bit. I just added basically this custom. Most of this is just from the example, except for this down here, right? Okay. And it's just getting the file name from the dialogue, opening the file and setting and config file name, right? Okay. So here's our save file. And this is what gets called from the XAML, right? All right. So on click, it's, it's going to call save file or save as file, right? On click, it's going to call save file. And as we saw earlier, so the config file is nothing and do a save as with a default config file. Otherwise, just save the testbed to the config file, right? Code behind for the XAML event for save as, and it just does the same thing. It says config file is nothing. Use the default config file. Otherwise, do the save as, you know, ask the user if they want to save it as the current config file, or maybe you want to add a dot one to it or whatever, right? Okay. And so here's our subroutine for save as, and you just pass it a file name. And it pulls up the save file dialogue as you saw, which is a windows thing. And this thing is, is pretty old. I don't know how this has been around forever. It seems like anyway, it just takes in the file name that sets the initial directory for it. And then the filter, as you saw in the globals, it just filters on text files, or you have the option of filtering on all files. So that's in this, if you don't know what this is, let me show you real quick. Let's see. So if you do a file save as, let's say, so see the save as type, you initially want to do text files because that's what we're looking for. So filters on text files, or you can filter on all files, right? And we'll talk about this XAML here in a second. So that's what this does right here is either filtering on text files or all files, right? Yeah, so it's, here's the filters where we left off at the default filter here. And then it's got this crazy question mark. And I'm not familiar with this. And it seems to work if you take the question mark off or leave it on there. I left it on there so I could talk about it in the video. I have no idea what it's for. But like I said, I can take this off and the Boolean works just fine. I can leave it on. I'm sure it means something in Microsoft land, but to me, it means nothing. So anyway, that's, that's what it is. I found this in the example. So I just left it. If you hit okay, you know, it gets the file name and saves the test bed and the config file. And then it said, saves the test bed using that file name and then updates the config file with the new file name. And here's our save test bed. Now this is a little more interesting. So I'm using a stream writer. I'm going to write it to the file that's passed in. And I thought about trying to use the xml writer and xml reader. Okay, so here's the xml writer class. And so in their example here, they are creating a button which is a control like what we have. Here's how it saves it. It just says save button or dim save button, they're just saving it as a string. Then they're just using this xml writer dot save. And I was like, wow, that's, that's pretty nice. And when you actually run an example like this, you get something that looks like, like this. And aside from the fact this thing is almost impossible to read. As you can say, this is a xml formatted string. And it's one big ass string. And it, but it, it looks like it has all the information we need. Let me pull it up in a better, in a better editor here. Okay, now this makes it a little easier to look at. Okay, so we got the type as a router node. It's got the name, the zindex. I mean, it's got everything. It's very nice. And of course, it's impossible to read anywhere else. And it's got the locations, the width, the height. The problem is, is when I went to use the xml reader, which is this guy up here, I could not, they're using the exact same example. I could not get this to work. It just kept complaining and complaining and complaining after messing around with it for probably two or three hours. I came into this xml writer and, and they had this serialization limitations of xml writer save. And you can go read it. I'm not going to read it to you. But anyway, it just talked about, you know, all the problems that this has. And this seemed a little bit convoluted anyway. I mean, so here's how you load it. So they're using a string reader to get the, to read the save the string. I don't know why you would need a string reader class to do that, but you do. Then you have to use this xml reader as xml or xml reader equals xml reader create. Okay, the string reader, right? And then once you create this xml reader, then you got to create your button. And you have to cast it from an xml reader dot load of your xml reader. And you got to cast it into a button. And I do this, this right here just seemed like nonsense to me. I'm like, what the, so I trashed it. I didn't like it. It was ugly. And it wasn't working. Now what I'm doing, I'm just, I'm just going through the collection of nodes and the collection of links. And I'm saying, okay, well, for each node in my collection of nodes, I'm going to say, I'm going to write node start, and then the node name, node type, the xy locations of it, and write them all in this file and say node end, right? And then the same for the links. And if you're wondering about the node start and the node end, when I'm doing the open, I can come back and say, okay, here's the start of the node. Okay, so I know all the information between these two points are the same node. Okay, so when we go to add more information this later, you know, my parser will know, okay, yeah, I know everything in here is part of the same node. All right, and same with the links. And the links are just link start, link end, and then the name of the link, what kind of link it is, and the two endpoints, node A and node B. And that's basically all we have right now, right? We haven't added really any config to any of our nodes. So, okay, so that's the same testbed. And that produces a file that looks like this. Now this to me is much simpler to read. And I could probably even put some spaces in between them. So yeah, so here's our two nodes, a router, you know, router node, their locations, and their names, right? And here's the link that goes in between them. To me, that's a lot simpler. You know, every time I add something, I'm gonna probably have to update, you know, my code. So when I start adding more config, I'm gonna have to add more code. Now I might be able to, you know, put this in its own little class, and then make the parser where it kind of reads it, but we'll do that in the future. Right now, this will be sufficient. And we can add to it as we go along. And if it starts getting too, too hard to maintain, when we add new config in here, then we'll have to, we'll just look at redesigning this. But right now it seems to work nice and easy to read. Because this is much better than that mess we were looking at earlier. Okay. And so the last thing I added is updated these node types with Cisco router node, Cisco switch node, and Xena test set. Because when we go to, to import this config, we're gonna have to know, I mean, right now our add router just, just only adds a Cisco router basically, right? But when we start adding Juniper routers and other types of routers, you know, we're gonna have to have a generic router node. We might change this node type to router, right? And then, then the node specific type or node manufacturer could be Cisco, we could put in model numbers if we want. Then when we open our config file up, it knows exactly what to build and how to populate all the fields, right? And that's why I wanted to break out the open config in a, in a separate video, because this is going to be a little more complex and then just writing text to a file, right? Don't forget, you can support the network engineering video blog by donation, using a credit card and PayPal or by purchasing products at the MUXHALL store. Details and links are in the description under this video. Well, that's it for this video. If you like the video, give it a big thumbs up, that helps, and hit the subscribe button, that really helps. If you have any questions or comments, post them in the comments under this video. Thanks for watching and I'll see you next time. Bye.