How can I create automatic GUI using XML file in C#?
Should I write a parser for the file and define a sort of "protocol" for the file's structure, and after the parse - create the GUI controls manually (respective to the data in the files)?
Or is there a better way? Is there a tool, or a built-in code in the .NET environment which can do that for me automatically?
(I am currently working with win forms, but I am willing to consider any other technology - as long as it's supported in MONO, since the code should be portable to Linux as well).
Glade is a RAD tool to enable quick & easy development of user interfaces for the GTK+ toolkit and the GNOME desktop environment.
The user interfaces designed in Glade are saved as XML, and by using the GtkBuilder GTK+ object these can be loaded by applications dynamically as needed.
By using GtkBuilder, Glade XML files can be used in numerous programming languages including C, C++, C#, Vala, Java, Perl, Python,and others.
I've used glade with C# and I was pleased with the result. Glade probably won't suit you directly, but you can at least borrow some ideas from it.
If you're going to use XML, then you should really know about XML schemas - these are XML files that describe the content of an XML file and DevStudio (and other editors) can read them and do autocompletion, which is useful. Also, you can validate an XML against a schema to ensure the content contains no structural errors.
Also, as Paul wrote, XAML is an XML system, but you'd need to use WPF framework to parse it.
WPF uses xml to define most things, it's known as xaml.
"Is there a tool, or a built-in code in the .NET environment which can do that for me automatically?"
There are various wrappers for .NET around XULRunner on code.google.com
Check out:
https://social.msdn.microsoft.com/Forums/en-US/554eefae-429f-495c-aee0-b2e971494ed0/how-do-i-create-a-gui-which-reads-xml-file-and-adds-controls-to-it-at-runtime?forum=csharplanguage
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
namespace WindowsFormsApplication_DynamicGUIFromXML
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
XDocument guiConfig = XDocument.Load(#"../../Gui.xml");
foreach (XElement item in from y in guiConfig.Descendants("Item") select y)
{
Control tmp = new Control();
switch (item.Attribute("type").Value)
{
case "Button":
tmp = new Button();
break;
case "TextBox":
tmp = new TextBox();
break;
}
tmp.Name = item.Attribute("name").Value;
tmp.Text = item.Attribute("text").Value;
tmp.Location = new Point(Int32.Parse(item.Attribute("x").Value), Int32.Parse(item.Attribute("y").Value));
Controls.Add(tmp);
}
}
}
}
// ***********************************************
// Contents of Gui.xml
// ***********************************************
//<?xml version="1.0" encoding="utf-8" ?>
//<Gui>
// <Item type="Button" name="foo" text="bar" x="100" y="100" />
// <Item type="TextBox" name="foo2" text="bar2" x="200" y="200" />
//</Gui>
// ***********************************************
Related
I'm using the roslyn API to write a DiagnosticAnalyzer and CodeFix.
After I have collected all strings and string-interpolations, I want to write all of them to a file but I am not sure how to do this the best way.
Of course I can always simply do a File.WriteAllText(...) but I'd like to expose more control to the user.
I'm also not sure about how to best trigger the generation of this file, so my questions are:
I do not want to hard-code the filename, what would be the best way to expose this setting to the user of the code-analyzer? A config file? If so, how would I access that? ie: How do I know the directory?
If one string is missing from the file, I'd like to to suggest a code fix like "Project contains changed or new strings, regenerate string file". Is this the best way to do this? Or is it possible to add a button or something to visual studio?
I'm calling the devenv.com executable from the commandline to trigger builds, is there a way to force my code-fix to run either while building, or before/after? Or would I have to "manually" load the solution with roslyn and execute my codefix?
I've just completed a project on this. There are a few things that you will need to do / know.
You will probably need to switch you're portable class library to a class library. otherwise you will have trouble calling the File.WriteAllText()
You can see how to Convert a portable class library to a regular here
This will potentially not appropriately work for when trying to apply all changes to document/project/solution. When Calling from a document/project/solution, the changes are precalcuated and applied in a preview window. If you cancel, an undo action is triggered to undo all changes, if you write to a file during this time, and do not register an undo action you will not undo the changes to the file.
I've opened a bug with roslyn but you can handle instances by override the preview you can see how to do so here
And one more final thing you may need to know is how to access the Solution from the analyzer which, Currently there is a hack I've written to do so here
As Tamas said you can use additional files you can see how to do so here
You can use additional files, but I know on the version I'm using resource files, are not marked as additional files by default they are embeddedResources.
So, for my users to not have to manually mark the resource as additonalFiles I wrote a function to get out the Designer.cs files associated with resource files from the csproj file using xDoc you can use it as an example if you choose to parse the csproj file:
protected List<string> GetEmbeddedResourceResxDocumentPaths(Project project)
{
XDocument xmldoc = XDocument.Load(project.FilePath);
XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
var resxFiles = new List<string>();
foreach (var resource in xmldoc.Descendants(msbuild + "EmbeddedResource"))
{
string includePath = resource.Attribute("Include").Value;
var includeExtension = Path.GetExtension(includePath);
if (0 == string.Compare(includeExtension, RESX_FILE_EXTENSION, StringComparison.OrdinalIgnoreCase))
{
var outputTag = resource.Elements(msbuild + LAST_GENERATED_TAG).FirstOrDefault();
if (null != outputTag)
{
resxFiles.Add(outputTag.Value);
}
}
}
return resxFiles;
}
For config files you can use the AdditionalFiles msbuild property, which is passed to the analyzers through the context. See here.
I need to make sure that the file given by the user is converted to the .txt file if contains text, before any further processing.
At the moment I have a switch statement checking for the specific formats and converting from those to the .txt format.
switch (extension)
{
case ".pdf":
//Convert from .pdf to .txt file
break;
case ".doc":
//Convert from .doc to .txt file
break;
default:
Console.WriteLine("The file could not be converted!");
break;
}
The problem is, I'd need something more generic to check if the given file is .txt or if it's not but could be converted, to do so.
Following L.B's advice I am going to reincarnate this.
Using the Tika Java Library In Your .Net Application With IKVM
This may sound scary and heretical but did you know it is possible to leverage Java libraries from .Net applications with no TCP sockets or web services getting caught in the crossfire? Let me introduce you to IKVM, which is frankly magic:
IKVM.NET is an implementation of Java for Mono and the Microsoft .NET Framework. It includes the following components:
A Java Virtual Machine implemented in .NET
A .NET implementation of the Java class libraries
Tools that enable Java and .NET interoperability
Using IKVM we have been able to successfully integrate our Dovetail Seeker search application with the Tika text extraction library implemented in Java. With Tika we can easily pull text out of rich documents from many supported formats. Why Tika? Because there is nothing comparable in the .Net world as Tika.
This post will review how we integrated with Tika. If you like code you can find this example in a repo up on Github.
Compiling a Jar Into An Assembly
First thing, we need to get our hands on the latest version of Tika. I downloaded and built the Tika source using Maven as instructed. The result of this was a few jar files. The one we are interested in is tika-app-x.x.jar which has everything we need bundled into one useful container.
Next up we need to convert this jar we’ve built to a .Net assembly. Do this using ikvmc.exe.
tika\build>ikvmc.exe -target:library tika-app-0.7.jar
Unfortunately, you will see tons of troublesome looking warnings but the end result is a .Net assembly wrapping the Java jar which you can reference in your projects.
Using Tika From .Net
IKVM is pretty transparent. You simply reference the the Tika app assembly and your .Net code is talking to Java types. It is a bit weird at first as you have Java versions of types and .Net versions. Next you’ll want to make sure that all the dependent IKVM runtime assemblies are included with your project. Using Reflector I found that the Tika app assembly referenced a lot of IKVM assemblies which do not appear to be used. I had to figure out through trial and error which assemblies where not being touched by the rich document extractions being done. If need be you could simple include all of the referenced IKVM assemblies with your application. Below I have done the work for you and eliminated all references to all the IKVM assemblies which appear to be in play.
16 assemblies down to 5. A much smaller deployment.
Using Tika
To do some text extraction we’ll ask Tika, very nicely, to parse the files we throw at it. For my purposes this involved having Tika automatically determine how to parse the stream and extract the text and metadata about the document.
public TextExtractionResult Extract(string filePath)
{
var parser = new AutoDetectParser();
var metadata = new Metadata();
var parseContext = new ParseContext();
java.lang.Class parserClass = parser.GetType();
parseContext.set(parserClass, parser);
try
{
var file = new File(filePath);
var url = file.toURI().toURL();
using (var inputStream = MetadataHelper.getInputStream(url, metadata))
{
parser.parse(inputStream, getTransformerHandler(), metadata, parseContext);
inputStream.close();
}
return assembleExtractionResult(_outputWriter.toString(), metadata);
}
catch (Exception ex)
{
throw new ApplicationException("Extraction of text from the file '{0}' failed.".ToFormat(filePath), ex);
}
}
One Important Cavet
Java has a concept called a ClassLoader which has something to do with how Java types are found and loaded. There is probably a better way around this but for some reason if you do not implement a custom ClassLoader and also set an application setting cueing the IKVM runtime about which .Net type to use as the ClassLoader.
public class MySystemClassLoader : ClassLoader
{
public MySystemClassLoader(ClassLoader parent)
: base(new AppDomainAssemblyClassLoader(typeof(MySystemClassLoader).Assembly))
{
}
}
Here is an example app.config telling IKVM where the ClassLoader is found.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ikvm:java.system.class.loader" value="TikaOnDotNet.MySystemClassLoader, TikaOnDotNet" />
</appSettings>
</configuration>
This step is very important. If IKVM cannot find a class loader, for some horrible reason, Tika will work fine but extract only empty documents with no metadata. The main reason this is troubling is that no exception is raised. For this reason we actually have a validation step in our application ensuring that the app setting is present and that it resolves to a valid type.
Demo
Here is a test demonstrating an extraction and the result.
[Test]
public void should_extract_from_pdf()
{
var textExtractionResult = new TextExtractor().Extract("Tika.pdf");
textExtractionResult.Text.ShouldContain("pack of pickled almonds");
Console.WriteLine(textExtractionResult);
}
Put simply rich documents like this go in.
And a TextExtractionResult comes out:
public class TextExtractionResult
{
public string Text { get; set; }
public string ContentType { get; set; }
public IDictionary<string, string> Metadata { get; set; }
//toString() override
}
Here is the raw output from Tika:
Conclusion
I hope this helps boost your confidence that you can use Java libraries in your .Net code and I hope my example repo will be of assistance if you need to do some work with Tika on the .Net platform. Enjoy.
Info to set this up:
Use Nuget to look up TikaOnDotnet and install both TikaOnDotnet & TikaOnDotnet.TextExtractor to your project. Here's the code to test it out on a Winform App:
public partial class Form1 : Form
{
private System.Windows.Forms.TextBox textBox1;
private TextExtractor _textExtractor;
public Form1()
{
InitializeComponent();
_textExtractor = new TextExtractor();
textBox1 = new System.Windows.Forms.TextBox();
textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
textBox1.Multiline = true;
textBox1.Name = "textBox1";
textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
textBox1.AllowDrop = true;
textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
Controls.Add(this.textBox1);
Name = "Drag/Drop any file on to the TextBox";
ClientSize = new System.Drawing.Size(867, 523);
}
private void textBox1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (files != null && files.Length != 0)
{
TextExtractionResult textExtractionResult = _textExtractor.Extract(files[0]);
textBox1.Text = textExtractionResult.Text;
}
}
}
Edit: The original blog page has moved to but there is no 302 perm redirect http://clarify.dovetailsoftware.com/kmiller/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm/
I'm trying to implement java autocomplete in one of my ScintillaNET projects and am having an issue. I've been following all the steps required
Ensure that ScintillaNET (and required .dlls) are located in my PATH variable.
Added the CustomLocation and Language params values to my editor
Below is my code for review, and I have ensured that I have the params set correctly...I'm just lost.
Scintilla sciEditor = (Scintilla)selectedTab.Controls["sciEditor"];
using (StreamReader sr = new StreamReader(fileName))
{
String line = sr.ReadToEnd();
sciEditor.Text = line;
}
if (ext == "java")
{
sciEditor.ConfigurationManager.Language = "java";
sciEditor.ConfigurationManager.CustomLocation = #"C:\java.xml";
sciEditor.CharAdded += new EventHandler<CharAddedEventArgs>(sciEditor_CharAdded);
}
So you can see I read the text into the Scintilla editor, and if the files ext is java (which I parse above this block, and get valid answer), then I set the editors languaget to java, and set my custom location to a java.xml file
<?xml version="1.0" encoding="utf-8"?>
<ScintillaNET>
<Language Name="java">
<AutoComplete FillUpCharacters=".([" SingleLineAccept="True" IsCaseSensitive="False">
<List>
abstract assert boolean break byte case catch char class continue default do double else enum extends
final finally float for if import int interface long native new package private protected public return
short static strictfp super switch synchronized this throw throws transient try void volatile while
</List>
</AutoComplete>
<Indentation TabWidth="4" SmartIndentType="cpp" />
<Lexer LexerName="java" LineCommentPrefix="//" StreamCommentPrefix="/* " StreamCommentSuffix=" */" >
<Keywords List="0" Inherit="False">
abstract assert break case catch continue default do else extends final finally for if import interface
native new package private protected public return strictfp super switch synchronized this throw throws
transient try volatile while
</Keywords>
<Keywords List="1" Inherit="False">
boolean byte char class double enum float int long short static
</Keywords>
</Lexer>
</Language>
</ScintillaNET>
And whenever I deploy (and have the .xml in my C:\ folder (or deployed beside my executable) it doesn't apply any styling (and the autocomplete is empty). Besides downloading and recompiling my own, I have no idea what's wrong.
Same issue happened to me today and I got banned for asking such a question.
Shame on ScintillaNET developer(s).
Trying to define myself a custom language, but, ended up you can't do it.
So, what I did is I used pre-built language as a NAME, and then extended that LANGUAGE instead of defining my own, which ScintillaNET cant find. Hopefully you understand, it took me four days to figure it, such a stupid shit. Thanks to Charles:) - dreamincode.net for a hint, as my head is blown atm.
*Please note that this is not for a web based application, it's windows based.
I'm building an application where I will need the user to submit simple javascripts that will be run by the application.
The scripts will call functions that are part of the c# build.
An example:
C# code:
public void helloWorld()
{
Debug.WriteLine("hello world");
}
Javascript submitted by user:
helloWorld();
The JavaScript would be parsed by the application at runtime and then call the required functions in my C# code.
Why?..
My app will be used by people with very little programming experience, they enter very simple JavaScripts and the app will attempt to automate a few tasks on the users computer. So my reason for using JavaScript is because it's simple and very easy to learn for someone with little experience.
It sounds like you want a JavaScript parser for your application. To be honest, I dont think what you're doing is possible, considering the context of the script and your code is different. However, this project seems to be doing something that may get you to the right place:
http://javascriptdotnet.codeplex.com/
Personally, I would think making some kind of XML format would be useful (like how UrlRewriter.net makes rewriting URLs easy):
<xml>
<commands>
<!-- Expose a Set of Condition Objects to Select From -->
<if condition="YourApplication.Conditions.RightClickOnDesktop">
<print text="HelloWorld" />
</if>
</commands>
Here is an example running a javascript code which, in turn, invokes a c# method
[System.Runtime.InteropServices.ComVisible(true)]
public class CSharpClass
{
public void MsgBox(string s)
{
MessageBox.Show(s);
}
}
-
Type scriptType = Type.GetTypeFromCLSID(Guid.Parse("0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC"));
dynamic obj = Activator.CreateInstance(scriptType, false);
obj.Language = "Javascript";
obj.AddObject("mywindow", new CSharpClass(), true);
var result = obj.Eval(
#"
function test(){
mywindow.MsgBox('hello');
}
test();
"
);
Why do you "need the user to submit simple javascripts"? What is your application and what do users need it to do? Why have you decided a scripting language is the way to do this? I'm not saying that is the wrong answer, but that you have not justified this conclusion.
If your app will be used by "people with very little programming experience" I do not recommend implementing a scripting language. Basic concepts like source code and variables are very difficult for non-programmers to understand.
I suggest first investigating macro recording for user scripting. For .NET there is UI Automation and the White automation framework.
VS 2008
I have this code snippet I found on a VB website.
But for some reason I am having trouble converting it to C#.
My.Computer.Network.IsAvailable
Many thanks,
using System.Net.NetworkInformation;
internal class Program
{
private static void Main()
{
NetworkInterface.GetIsNetworkAvailable();
}
}
Yes, garethm is right, this class (Network) is from a VB.NET library - you need to reference the Microsoft.VisualBasic assembly if using in a C# project.
Microsoft.VisualBasic.Devices.Network n = new Microsoft.VisualBasic.Devices.Network();
if (n.IsAvailable)
{
// do stuff
}
Works for me - my network is available :).
As far as how Network relates to NetworkInterface class, it depends on what you want to do next. For instance, Network has such nice stuff as NetworkAvailabilityChanged event, and UploadFile method. On the other hand, NetworkInterface can give you a bunch of specific technical info such as speed or whether it supports multicast.
BTW, there is nothing undocumented about using a class from Microsoft.VisualBasic namespace - it's the core idea behind .NET that you can use classes from assemblies regardless of the language they were written in.
What I generally do is write a small app, then load then project in Reflector and disassemble it.
but you can use this class:
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged
Isn't the whole "My" thing from a VB library?
This appears to work. It's probably very undocumented usage though:
Microsoft.VisualBasic.Devices.Network net = new Microsoft.VisualBasic.Devices.Network();
if (net.IsAvailable)
{
Text = "Network is available";
}
else
{
Text = "Network unavailable";
}
Note that I needed to add a reference to Microsoft.VisualBasic to my project.