I have a Visio ER diagram and want to read the database properties (Columns, Primary, Foreign key, data type) information from an Entity. Also want to find the parent and child tables associated. How can I programmatically achieve it using C#?
I am using Interop Visio library and can read the pages and shape from ER diagram but don't know which functions or methods in Visio interop will let me get properties information from a Shape.
Below is the code I am using and I am not getting any property using it. My ER diagram have just two entities a Parent and a Child table.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Office.Interop.Visio;
namespace Visio_POC
{
public partial class Load_Visio : Form
{
static string strProperties = "";
public Load_Visio()
{
InitializeComponent();
string strFileName = "\\Visio_POC\\POC_Visio.vsd";
Microsoft.Office.Interop.Visio.Application vsApp = new Microsoft.Office.Interop.Visio.Application();
Microsoft.Office.Interop.Visio.Document docVisio = vsApp.Documents.Add(strFileName);
Page pgVisio = docVisio.Pages[1];
Shapes shpVisio = pgVisio.Shapes;
int intCnt = shpVisio.Count;
string[] strShapeText = new string[intCnt];
printProperties(pgVisio.Shapes);
txtProperties.Text = strProperties;
}
public static void printProperties(Shapes shapes)
{
// Look at each shape in the collection.
foreach (Shape shape in shapes)
{
// Use this index to look at each row in the properties
// section.
short iRow = (short) VisRowIndices.visRowFirst;
// While there are stil rows to look at.
while (shape.get_CellsSRCExists(
(short) VisSectionIndices.visSectionProp,
iRow,
(short) VisCellIndices.visCustPropsValue,
(short) 0) != 0)
{
// Get the label and value of the current property.
string label = shape.get_CellsSRC(
(short) VisSectionIndices.visSectionProp,
iRow,
(short) VisCellIndices.visCustPropsLabel
).get_ResultStr(VisUnitCodes.visNoCast);
string value = shape.get_CellsSRC(
(short) VisSectionIndices.visSectionProp,
iRow,
(short) VisCellIndices.visCustPropsValue
).get_ResultStr(VisUnitCodes.visNoCast);
// Print the results.
//Console.WriteLine(string.Format(
// "Shape={0} Label={1} Value={2}",
// shape.Name, label, value));
strProperties = strProperties + shape.Name + " - " + label + " - " + value;
// Move to the next row in the properties section.
iRow++;
}
// Now look at child shapes in the collection.
if (shape.Master == null && shape.Shapes.Count > 0)
printProperties(shape.Shapes);
}
}
}
}
The database reverse engineering is a closed solution. There was a book "Database Modeling" by Terry Halpin which covered this. Alternatively you could peruse my article at http://blog.bvisual.net/2014/03/26/creating-a-schema-from-visio-external-data-record-sets/ for an idea of how you could do it yourself.
Related
I'm trying to programatically fill in some ContentControls inside a MS Word document with C#.
So far I've been able to open the document and find all the controls, but they come back as generic ContentControl objects. Inspecting them with a debugger just reveals a generic System.__ComObject.
From the docs I can see that some of the controls should have a .Text property, but I cannot figure out how to access it.
I can determine the type of the control using the switch statement you see below, but it doesn't really help me -- I don't know what class to cast the object to (if that's even what I'm supposed to do).
There is a class called PlainTextContentControl but it exists in Microsoft.Office.Tools.Word, but the Application and Document and ContentControl live under Microsoft.Office.Interop.Word and these do not play nicely together.
So I'm lost. How do I access the Text property? Here's what I've got:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Word;
//using Microsoft.Office.Interop.Word;
using Microsoft.Office.Tools.Word;
using ContentControl = Microsoft.Office.Interop.Word.ContentControl;
using Document = Microsoft.Office.Interop.Word.Document;
namespace ConsoleApplication1
{
internal class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Opening Word Application...");
var app = new Application();
try
{
Console.WriteLine("Loading document...");
var doc = app.Documents.Open(
#"C:\blahblah\template3.docx");
Console.WriteLine("Finding controls...");
var controls = GetAllContentControls(doc);
foreach (var control in controls)
{
Console.WriteLine(control.Tag);
switch (control.Type)
{
case WdContentControlType.wdContentControlText:
var pt = control as PlainTextContentControl;
Console.WriteLine("hit"); // pt is null
break;
}
}
doc.Close();
}
finally
{
app.Quit();
}
}
public static List<ContentControl> GetAllContentControls(Document wordDocument)
{
var ccList = new List<ContentControl>();
foreach (Range range in wordDocument.StoryRanges)
{
var rangeStory = range;
do
{
try
{
foreach (ContentControl cc in rangeStory.ContentControls)
{
ccList.Add(cc);
}
}
catch (COMException)
{
}
rangeStory = rangeStory.NextStoryRange;
} while (rangeStory != null);
}
return ccList;
}
}
}
I should note that I'm using JetBrains Rider instead of Visual Studio. If this is impossible to do with Rider for some reason, I can probably obtain a copy of VS.
You can just use the code resemble the following:
switch (control.Type)
{
case WdContentControlType.wdContentControlText:
var text = control.Range.Text;
//var pt = control as PlainTextContentControl;// pt is null
Console.WriteLine(text);
break;
case WdContentControlType.wdContentControlRichText:
var richText = control.Range.Text;
//var pt1 = control as PlainTextContentControl;// pt1 is null
Console.WriteLine(richText);
break;
}
This code is replacing the text with an image but its placing the multiple copies of an image and placing them in the beginning of the document. I want the image to be placed at the same position where text was present. My find text is available in the table cell. Is it due to that?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using word = Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;
//using System.Drawing;
namespace WritingIntoDocx
{
[ComVisible(true)]
public interface IMyClass
{
void DocumentDigitalSign(string filep,string findt,string replacet);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Program : IMyClass
{
public void DocumentDigitalSign(string filep, string findt, string imagepath)
{
string filepath = filep;
string Findtext = findt;
word.Application app = new word.Application();
word.Document doc = app.Documents.Open(filepath);
word.Range myStoryRange = doc.Range();
//First search the main document using the Selection
word.Find myFind = myStoryRange.Find;
myFind.Text = Findtext; myFind.Replacement.Application.Selection.InlineShapes.AddPicture(imagepath);
myFind.Forward = true;
myFind.Wrap = word.WdFindWrap.wdFindContinue;
myFind.Format = false;
myFind.MatchCase = false;
myFind.MatchWholeWord = false;
myFind.MatchWildcards = false;
myFind.MatchSoundsLike = false;
myFind.MatchAllWordForms = false;
myFind.Execute(Replace: word.WdReplace.wdReplaceAll);
//'Now search all other stories using Ranges
foreach (word.Range otherStoryRange in doc.StoryRanges)
{
if (otherStoryRange.StoryType != word.WdStoryType.wdMainTextStory)
{
word.Find myOtherFind = otherStoryRange.Find;
myOtherFind.Text = Findtext; myOtherFind.Replacement.Application.Selection.InlineShapes.AddPicture(imagepath);
myOtherFind.Wrap = word.WdFindWrap.wdFindContinue;
myOtherFind.Execute(Replace: word.WdReplace.wdReplaceAll);
}
// 'Now search all next stories of other stories (doc.storyRanges dont seem to cascades in sub story)
word.Range nextStoryRange = otherStoryRange.NextStoryRange;
while (nextStoryRange != null)
{
word.Find myNextStoryFind = nextStoryRange.Find;
myNextStoryFind.Text = Findtext;
myNextStoryFind.Replacement.Application.Selection.InlineShapes.AddPicture(imagepath);
myNextStoryFind.Wrap = word.WdFindWrap.wdFindContinue;
myNextStoryFind.Execute(Replace: word.WdReplace.wdReplaceAll);
nextStoryRange = nextStoryRange.NextStoryRange;
}
}
app.Documents.Save();
app.Documents.Close();
}
}
}
Replacement.Application is a reference to the application object. When you call AddPicture() on that, the picture is immediately inserted at the current position before the find operation is even executed.
I see two possibilities:
Load the picture, place it into the Windows clipboard and then execute the find operation specifying "^c" as replacement text. Word will replace "^c" with the current content of the clipboard. This is what the documentation says:
ReplaceWith
Type: System.Object
Optional Object.
The replacement text. To delete the text specified by the Find argument, use an empty string (""). You specify special characters and advanced search criteria just as you do for the Find argument. To specify a graphic object or other non-text item as the replacement, move the item to the Clipboard and specify "^c" for ReplaceWith.
Do not use wdReplaceAll, but wdReplaceNone, so that the find operation itself does not do any replacing. But you then have the chance to insert your content at the place found. Do that in a loop until no more occurrence is found.
i'm rather new and am trying to create a C# program that retrieves post from Facebook using FB API.
I have a word count feature which checks against a negative word dictionary.
This means that it would display the negative word along with its frequency occurrence.
The problem i'm facing now is that, i want to display the posts that contains this negative words. However, if the negative word exists 3 times in the post, the post would appear thrice. How do i solve this problem?
Below is my code:
(For designer)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace empTRUST
{
public partial class PostAnalysis : Form
{
DBStatusDL ad;
string target_fbid;
public PostAnalysis(string target_fbid)
{
InitializeComponent();
this.target_fbid = target_fbid;
ad = new DBStatusDL();
}
private void button_Displayposts_Click(object sender, EventArgs e)
{
int i = 1;
var dir = new DirectoryInfo(Application.StartupPath + "\\Dictionary"); //Load the dictionary from debug folder
var ed = new matchingWordsWithPosts();
var rows = ad.LoadStatus(target_fbid); //Call the load status function based on fb_id
foreach (FileInfo file in dir.GetFiles()) //For loop, to loop through files
{
var dict = File.ReadAllLines(dir.FullName + "\\" + file);
foreach (var row in rows)
{
List<DataRow> words = ed.countWordsInStatus(row, dict); // Retrieves word dictionary returned from function
foreach (var word in words)
{
var item = new ListViewItem(new[] { i.ToString() ,word["Status_message"].ToString(), word["Status_time"].ToString() });
listViewPosts.Items.Add(item);
i++;
}
}
}
}
private void button_Back_Click(object sender, EventArgs e)
{
this.Close();
var abc = new AnalysisPage(target_fbid);
abc.Show();
}
}
}
(For class)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
namespace empTRUST
{
class matchingWordsWithPosts
{
public List<DataRow> countWordsInStatus(DataRow status, string[] dictArray)
{
List<DataRow> statusList = new List<DataRow>();
var words = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase); // local word dictionary is created here
foreach (var dictEntry in dictArray)
{
var wordPattern = new Regex(#"\w+");
string smallDictEntry = dictEntry.ToLower();
foreach (Match match in wordPattern.Matches(status["Status_message"].ToString()))
{
if (match.ToString() == smallDictEntry)
{
statusList.Add(status);
}
}
}
return statusList; // returns local word dictionary to receiving end
}
}
}
Because you didn't provide the countWordsInStatus() function, I can't know if that's the problem. However, it looks like the problem is that that function continues going through a post even if it has already matched one such word. To fix this, you could put continue; (or perhaps a break;, depending on the code you're using) after adding a post to the list you're returning. This would have the loop skip to the next post, and make sure it doesn't continue counting words in the post that has already had a match.
If you post that function, it should be much easier to understand the issue.
After a word is matched and you process the post exit the loop.
I have an issue with our firm's Normal.dotm related to the eastAsia attribute in styles.xml. If you're interested, you can find a history of the issue here. We can't just replace the template firmwide without overwriting custom styles/macros, etc. I have almost no experience with OpenXML, but I thought it might hold a solution to the problem. However, all the articles and tutorials I've found haven't been much help. They all reference the "Document" part and are focused on changing content rather than elements and attributes.
Basically, I need to loop through every <w:rFonts> element and change the w:eastAsia attribute from "Times New Roman" to "MS Mincho." This is the only part I feel confident about:
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace eastAsiaFix
{
class Program
{
static void Main(string[] args)
{
using (WordprocessingDocument myDocument = WordprocessingDocument.Open(#"C:\users\" + Environment.UserName + #"\Desktop\eastAsiaFix.dotm", true))
{
StyleDefinitionsPart styles = myDocument.MainDocumentPart.StyleDefinitionsPart;
if (styles == null)
{
return;
}
}
}
}
}
I think what I need is something like the following:
foreach (OpenXMLElement theStyle in styles.Styles.ChildElements)
{
if (theStyle.LocalName = "style")
{
theStyle.StyleRunProperties.RunFonts.EastAsia.Value = "MS Mincho"; //faking this
}
}
How do I get to the w:rFonts node and edit the eastAsia attribute?
I can think of two different solutions to change the East Asian font value.
The first solution just changes the East Asian font value for all RunFonts
under the Styles collection. This solutions would also change the East Asian
font value for the document default paragraph and run properties (DocDefaults class, w:docDefaults).
using (WordprocessingDocument myDocument = WordprocessingDocument.Open(#"C:\users\" + Environment.UserName + #"\Desktop\eastAsiaFix.dotm", true))
{
StyleDefinitionsPart stylesPart = myDocument.MainDocumentPart.StyleDefinitionsPart;
if (stylesPart == null)
{
Console.Out.WriteLine("No styles part found.");
return;
}
foreach(var rf in stylesPart.Styles.Descendants<RunFonts>())
{
if(rf.EastAsia != null)
{
Console.Out.WriteLine("Found: {0}", rf.EastAsia.Value);
rf.EastAsia.Value = "MS Mincho";
}
}
}
The second solution would be to change the East Asian font value
only for the style definitions (and not for the document default paragraph and run properties):
using (WordprocessingDocument myDocument = WordprocessingDocument.Open(#"C:\users\" + Environment.UserName + #"\Desktop\eastAsiaFix.dotm", true))
{
StyleDefinitionsPart stylesPart = myDocument.MainDocumentPart.StyleDefinitionsPart;
if (stylesPart == null)
{
Console.Out.WriteLine("No styles part found.");
return;
}
foreach(var style in stylesPart.Styles.Descendants<Style>())
{
foreach(var rf in style.Descendants<RunFonts>())
{
if(rf.EastAsia != null)
{
Console.Out.WriteLine("Found: {0}", rf.EastAsia.Value);
rf.EastAsia.Value = "MS Mincho";
}
}
}
}
I have an n3 file formate and i want to delete a node or triple from it how can i do it? should i use sparql query?please help me
i want to have an n3 file and want to delete a node from it.
i pass a graph that use in my parent form to this delete form and want to work with this graph that i create from an n3 file i mean i read this n3 file and convert it to a graph and send it to this form.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VDS.RDF;
using VDS.RDF.Parsing;
using VDS.RDF.Query;
using System.IO;
using System.Windows;
using System.Runtime.InteropServices;
using VDS.RDF.Writing;
namespace WindowsFormsApplication2
{
public partial class delete : Form
{
Graph gra = new Graph();
public delete(Graph initialValue)
{
InitializeComponent();
ValueFromParent = initialValue;
}
private void delete_Load(object sender, EventArgs e)
{
}
public Graph ValueFromParent
{
set
{
this.gra = value;
}
}
}
}
From the documentation on Working with Graphs please see the section titled Asserting and Retracting triples which makes mention of the Assert() and Retract() methods which can be used to do what you've asked.
For example to delete a specific Triple:
//Assuming you already have the triple to delete in a variable t
g.Retract(t);
Or perhaps more usefully deleting all Triples that match a specific Node:
g.Retract(g.GetTriplesWithSubject(g.CreateUriNode(new Uri("http://example.org"))));
If you aren't sure whether a specific Node exists you can do something like the following:
INode n = g.GetUriNode(new Uri("http://example.org"));
//If n is null then the specified Node does not exist in the Graph
if (n != null)
{
g.Retract(g.GetTriplesWithSubject(n));
}
Note that you can't directly delete a Node from the Graph other than by removing all Triples that have it in the Subject/Object position. Also note that this does not remove it from the collection provided by the Nodes property of the Graph currently.
Yes you can also do this via SPARQL but for just removing a few triples that is very much overkill unless you need to remove triples based on some complex criteria which is not easily expressed directly using API selection and retraction methods.