TreeItem set multiple children under a parent/child - javafx

I am trying to get a list of equipment IDs to show under one data structure, instead of a listing with the equipment name alongside each ID.
I'm trying to get it to show:
Site Equipment
Inlet P1
M&C-SP2500
329
Sick Maihak-MCS 100e
330
336
538
Inlet P2
etc....
The data is from MySQL query and using an ObservableList.
private ObservableList<Customer_EquipTree> equiptrees;
TreeItem<String> rootItem = new TreeItem<String>("Site Equipment");
rootItem.setExpanded(true);
for (Customer_EquipTree equiptree : equiptrees) {
TreeItem<String> equip = new TreeItem<String>(equiptree.getEquipment());
TreeItem<String> clID = new TreeItem<String>(equiptree.getclID().toString());
boolean found = false;
for (TreeItem<String> siteDes : rootItem.getChildren()) {
if (siteDes.getValue().contentEquals(equiptree.getSiteDesignation())) {
siteDes.getChildren().add(equip);
equip.getChildren().add(clID);
found = true;
break;
}
}
if (!found) {
TreeItem<String> siteDes = new TreeItem<String>(equiptree.getSiteDesignation());
rootItem.getChildren().add(siteDes);
siteDes.getChildren().add(equip);
equip.getChildren().add(clID);
locationTreeView.setRoot(rootItem);
}
}
This is how I have
public class Customer_EquipTree {
private String SiteDesignation;
private String Equipment;
private Integer Checklistid;
private Integer clID;
public Customer_EquipTree(String SiteDesignation, String Equipment, Integer Checklistid, Integer clID) {
this.SiteDesignation = SiteDesignation;
this.Equipment = Equipment;
this.Checklistid = Checklistid;
this.clID = clID;
}
public String getSiteDesignation() {
return SiteDesignation;
}
public void setSiteDesignation(String SiteDesignation) {
this.SiteDesignation = SiteDesignation;
}
public String getEquipment() {
return Equipment;
}
public void setEquipment(String Equipment) {
this.Equipment = Equipment;
}
public Integer getChecklistid() {
return Checklistid;
}
public void setChecklistid(Integer Checklistid) {
this.Checklistid = Checklistid;
}
public Integer getclID() {
return clID;
}
public void setclID(Integer clID) {
this.clID = clID;
}
#Override
public String toString() {
return SiteDesignation + " " + Equipment.toString();
}
}

It seems to me that your Customer_EquipTree is basically a tuple of site, equipment and id and there is one for every id. It looks you need to look for existing equipment the same way you look for existing sites.
You should create a helper method for this to avoid code duplication:
public static <T> TreeItem<T> findOrInsert(TreeItem<T> parent, T childValue) {
for (TreeItem<T> child : parent.getChildren()) {
if (child.getValue().equals(childValue)) {
return child;
}
}
TreeItem<T> result = new TreeItem<T>(childValue);
parent.getChildren().add(result);
return result;
}
for (Customer_EquipTree equiptree : equiptrees) {
TreeItem<String> siteDes = findOrInsert(rootItem, equiptree.getSiteDesignation());
TreeItem<String> equip = findOrInsert(siteDes, equiptree.getEquipment());
equip.getChildren().add(new TreeItem<>(equiptree.getclID().toString()));
}
BTW: using ORDER BY in your sql query would allow you to simplify the tree creation a bit, since you can be sure the items with matching site/equipment values occur next to each other in the ResultSet, e.g.
TreeItem<String> rootItem = new TreeItem<String>("Site Equipment");
try (Statement st = conn.createStatement()) {
ResultSet rs = st.executeQuery("SELECT siteDesignation, equipment, clID FROM Customer_EquipTree ORDER BY siteDesignation, equipment");
String currentSite = null;
String currentEquipment = null;
TreeItem<Sting> tiSite = null;
TreeItem<String> tiEquipment = null;
while (rs.next()) {
String site = rs.getString(1);
String equipment = rs.getString(2);
String id = rs.getString(3);
if (!site.equals(currentSite)) {
currentSite = site;
tiSite = new TreeItem<>(site);
rootItem.getChildren().add(tiSite);
currentEquipment = null; // equipment needs to be replaced too
}
if (!equipment.equals(currentEquipment)) {
currentEquipment = equipment;
tiEquipment = new TreeItem<>(equipment);
tiSite.getChildren().add(tiEquipment);
}
tiEquipment.getChildren().add(new TreeItem<>(id));
}
}

Related

JavaFX: Updating Part property in one list updates the other

New to JavaFX, be patient please.
APPLICATION: Inventory management system. There are parts, products. Products can have associated parts. In the adding/modifying product screen you can add parts that are associated with it from the list of all the parts available.
ISSUE: All parts list updates the inventory level to that of what the associated parts inventory level updated too. I need it to remain the same (ill handle the subtraction once this is figured out).
RELEVANT CODE:
public class ProductDetailController implements Initializable {
....
public static ObservableList<Part> newListForTV = FXCollections.observableArrayList();
public static ObservableList<Part> exListForTV = FXCollections.observableArrayList();
private void SetupGrids() {
colPartID.setCellValueFactory(new PropertyValueFactory<>("partID"));
colPartName.setCellValueFactory(new PropertyValueFactory<>("name"));
colInventory.setCellValueFactory(new PropertyValueFactory<>("inStock"));
colPrice.setCellValueFactory(new PropertyValueFactory<>("price"));
tvExistingParts.setItems(exListForTV);
colNewPartID.setCellValueFactory(new PropertyValueFactory<>("partID"));
colNewPartName.setCellValueFactory(new PropertyValueFactory<>("name"));
colNewInventory.setCellValueFactory(new PropertyValueFactory<>("inStock"));
colNewPrice.setCellValueFactory(new PropertyValueFactory<>("price"));
//
for (Part nPartsAll : Inventory.allParts) {
if (!newListForTV.contains(nPartsAll)) {
newListForTV.addAll(Inventory.allParts);
}
}
tvNewParts.setItems(newListForTV);
}
public void AddPart() {
boolean partAvailable = false;
int selectionCheck = tvNewParts.getItems().size();
if (selectionCheck > 0) {
partN = tvNewParts.getSelectionModel().getSelectedItem();
partAvailable = CheckPartInventory(partN);
if (partAvailable) {
partEX = CheckIfContainsPart(exListForTV, partN);
if (partEX == null) {
tvExistingParts.getItems().add(partN);
partEX = CheckIfContainsPart(exListForTV, partN);
if (partEX.getPartID() == partN.getPartID()) {
ClearInventoryOfPart(partEX);
partEX.setInStock(1);
}
} else {
partEX.setInStock(partEX.getInStock() + 1);
tvExistingParts.refresh();
}
}
}
}
private Boolean CheckPartInventory(Part part) {
boolean available = false;
int invPartInven = 0, invPartMin = 0, invPartMax = 0;
for (Part invPart : Inventory.allParts) {
if (invPart.getPartID() == part.getPartID()) {
invPartInven = invPart.getInStock();
invPartMin = invPart.getMin();
invPartMax = invPart.getMax();
if (invPartInven <= invPartMin || invPartInven >= invPartMax || invPartInven == 0) {
available = false;
} else {
available = true;
}
}
}
return available;
}
private void CommitSaveOfProduct() {
try {
if (newProduct == false) {
exListForTV.forEach(part -> {
Product.addAssociatedPart(part);
});
Inventory.updateProduct(new AssociatedProParts(Integer.parseInt(tfID.getText()), tfName.getText(), Double.parseDouble(tfPrice.getText()),Integer.parseInt(tfINV.getText()),Integer.parseInt(tfMin.getText()),Integer.parseInt(tfMax.getText()),exListForTV));
genericClass.DisplayInformationAlert("Existing product has been successfully saved.");
tvExistingParts.getItems().clear();
genericClass.GoToPage(btnCancel, constants.productNavLocation, constants.productPageTitle);
} else if (newProduct == true) {
Inventory.addProduct(new AssociatedProParts(tfName.getText(), Double.parseDouble(tfPrice.getText()),Integer.parseInt(tfINV.getText()),Integer.parseInt(tfMin.getText()),Integer.parseInt(tfMax.getText()),exListForTV));
genericClass.DisplayInformationAlert("New product has been successfully saved.");
tvExistingParts.getItems().clear();
genericClass.GoToPage(btnCancel, constants.productNavLocation, constants.productPageTitle);
}
} catch (Exception ex) {
genericClass.DisplayErrorAlert("Saving Product has failed...");
}
}
........
}
public class Inventory {
public static ObservableList<Product> allProducts = FXCollections.observableArrayList();
public static ObservableList<Part> associatedParts = FXCollections.observableArrayList();
public static ObservableList<Part> allParts = FXCollections.observableArrayList();;
.......
}
public class AssociatedProParts extends Product {
public static ObservableList<Part> aParts = FXCollections.observableArrayList();
public AssociatedProParts() {
super(0,"",0,0,0,0);
}
public AssociatedProParts(int productID, String name, double price, int inStock, int min, int max, ObservableList<Part> associatedParts) {
super(productID, name, price, inStock, min, max);
aParts.addAll(associatedParts);
}
public AssociatedProParts(String name, double price, int inStock, int min, int max, ObservableList<Part> associatedParts) {
super(name, price, inStock, min, max);
aParts.addAll(associatedParts);
}
public void setAParts(Part part) {
aParts.add(part);
Inventory.associatedParts.addAll(aParts);
}
public ObservableList<Part> getAParts() {
return aParts;
}
}
LASTLY: My problem is the newListForTV updates the inventory level to that of the exListForTV. newListForTV needs to not change. This is driving me nuts. And yes, I still need to go through and clean things up and abstract things to not be so cluttered. Right now, i just need this to work.
Though I would like to find a more efficient way. I have managed to get this to work by adding another getter/setter to parts to account for the change in stock.

How to get an auto-sorting TableView?

I have a TableView with a list of items (Transaction) and want it to sort, so that all positive values are above the negative ones. This is the only requirement.
What I have until now:
expensesTableView.sortPolicyProperty().set(
new Callback<TableView<Transaction>, Boolean>() {
#Override
public Boolean call(TableView<Transaction> param) {
Comparator<Transaction> c = (a, b) -> {
if (a.getValue().contains("-") ^ b.getValue().contains("-")) { //getValue() returns a String
return a.getValue().contains("-") ? 1 : -1;
}
return 0;
};
FXCollections.sort(expensesTableView.getItems(), c);
return true;
};
});
This wasn't my idea, I found this on the net, so don't ask if it looks like a strange way to achieve that. The real problem is, that the table doesn't sort on its own when a new item is added/edited/deleted. I need to click the header 3 times and then it does what I want.
How can I have a list that is always sorted correctly?
I tried adding a ChangeListener and sort on change. But besides that this is an ugly way to do that, it didn't even work... I'm at the end of ideas.
The bitwise OR in the comparator didn't work in my tests, so I've changed it to a normal one, and it's also not checking for change in the value of items from the list.
I wonder if it might be more efficient to do a numeric check rather than a String check, negatives could still sort out below, but I guess the conversion might cost more?
My first idea with SortedList in the comments was actually related to keeping the original sorted order, to be restored after the user has changed the sort, so was off the mark.
Edited to add: Just to clarify, it's the act of keeping the source list sorted that keeps the table list sorted.
public class TestApp extends Application {
private int c;
private ObservableList<TestTransaction> sortedOL;
private final Comparator<TestTransaction> comp = (TestTransaction a, TestTransaction b) -> {
if (a.getValue().contains("-") || b.getValue().contains("-")) {
return a.getValue().contains("-") ? 1 : -1;
}
return 0;
};
private TableView<TestTransaction> tableView;
#Override
public void start(Stage primaryStage) {
ArrayList<TestTransaction> rawList = new ArrayList<>();
for (int i = 1; i < 20; i++) {
int v = i * 3;
if (v % 2 > 0) {
v = v * -1;
}
c = i;
rawList.add(new TestTransaction(Integer.toString(v), "Item " + c));
}
sortedOL = FXCollections.observableArrayList(rawList);
sortedOL.addListener((ListChangeListener.Change<? extends TestTransaction> c1) -> {
if (c1.next() && (c1.wasAdded() || c1.wasRemoved())) {
FXCollections.sort(sortedOL, comp);
}
});
FXCollections.sort(sortedOL, comp);
tableView = new TableView<>(sortedOL);
TableColumn<TestTransaction,String> valCol = new TableColumn<>("Value");
valCol.setCellValueFactory(new PropertyValueFactory("value"));
TableColumn<TestTransaction,String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new PropertyValueFactory("name"));
tableView.getColumns().setAll(valCol, nameCol);
BorderPane tpane = new BorderPane();
Button btnAdd = new Button("Add");
btnAdd.setOnAction(a -> {addTransaction();});
ToolBar tb = new ToolBar(btnAdd);
tpane.setTop(tb);
tpane.setCenter(tableView);
tpane.setPrefSize(600, 600);
Scene scene = new Scene(tpane, 600, 600);
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.show();
}
private void addTransaction() {
c++;
int v = (int) Math.floor(Math.random() * 50);
if (v % 2 > 0) {
v = v * -1;
}
sortedOL.add(new TestTransaction(Integer.toString(v), "New Item " + c));
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
public class TestTransaction {
private String value;
private String name;
public TestTransaction(String value, String name) {
this.value = value;
this.name = name;
}
/**
* #return the value
*/
public String getValue() {
return value;
}
/**
* #return the name
*/
public String getName() {
return name;
}
}
If you want to use SortedList, meaning you could inline the comparator:
sortedOL = FXCollections.observableArrayList(rawList);
SortedList sorted = new SortedList(sortedOL, comp);
tableView = new TableView<>(sorted);

How to accept mine if any conflicts occur while pull-rebase in JGit

I have a piece of code that does pull with rebase:
private void pullWithRebase(Git git) throws GitAPIException {
git.checkout().setName("master").call();
List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
String remoteMasterBranchName = "refs/remotes/origin/master";
for (Ref ref : branches) {
if (remoteMasterBranchName.equals(ref.getName())) {
PullResult result = git.pull().setRemoteBranchName("master").setRebase(true).call();
return;
}
}
}
However it doesn't work if any conflicts occur while merging. If they do occur, I want to accept mine
I ended up just merging two branches and directly resolving any conflicts by modifying files.
private static final String CONFLICT_HEAD_MARKER = "<<<<<<<";
private static final String CONFLICT_BORDER_MARKER = "=======";
private static final String CONFLICT_UPSTREAM_MARKER = ">>>>>>>";
private boolean acceptHead;
public void resolve(File file) throws IOException {
File temp = new File(file.getParent(), "temp" + System.currentTimeMillis());
try(BufferedReader reader = new BufferedReader(new FileReader(file));
BufferedWriter writer = new BufferedWriter(new FileWriter(temp))) {
String currentLine;
boolean removePartition = false;
while((currentLine = reader.readLine()) != null) {
if (currentLine.contains(CONFLICT_HEAD_MARKER)) {
removePartition = !acceptHead;
continue;
} else if (currentLine.contains(CONFLICT_BORDER_MARKER)) {
removePartition = acceptHead;
continue;
} else if (currentLine.contains(CONFLICT_UPSTREAM_MARKER)) {
removePartition = false;
continue;
}
if (!removePartition) {
writer.write(currentLine + System.getProperty("line.separator"));
}
}
}
FileUtils.forceDelete(file);
FileUtils.moveFile(temp, file);
}

Create Multimedia component with Metadata fields.using core service

I am creating Multimedia components using core service and everything is working fine. But when Metadata schema fields are defined on the Multimedia schema using which I am creating my Multimedia components then I am getting following error:-
Unable to find http://www.tridion.com/ContentManager/5.0/DefaultMultimediaSchema:Metadata.
This message is displayed when I have given Default Multimedia schema's TCM ID for Multimedia component. As metadata fields are saved in Tridion Database so I first have to retrieve these fields from broker or what is the best solution for this, please suggest. Below is the sample code. Please modify it if someone have any idea for providing default value for metadatafields and how to retrieve them (with/without querying broker DB):-
public static string UploadMultiMediaComponent(string folderUri, string title, string schemaID)
{
core_service.ServiceReference1.SessionAwareCoreService2010Client client = new SessionAwareCoreService2010Client();
client.ClientCredentials.Windows.ClientCredential.UserName = "myUserName";
client.ClientCredentials.Windows.ClientCredential.Password = "myPassword"; client.Open();
ComponentData multimediaComponent = (ComponentData)client.GetDefaultData(
ItemType.Component, folderUri);
multimediaComponent.Title = title;
multimediaComponent.ComponentType = ComponentType.Multimedia;
multimediaComponent.Schema.IdRef =schemaID;
//multimediaComponent.Metadata = "";
StreamUpload2010Client streamClient = new StreamUpload2010Client();
FileStream objfilestream = new FileStream(#"\My Documents\images.jpg",
FileMode.Open, FileAccess.Read);
string tempLocation = streamClient.UploadBinaryContent("images.jpg",
objfilestream);
BinaryContentData binaryContent = new BinaryContentData();
binaryContent.UploadFromFile = tempLocation;
binaryContent.Filename = "images.jpg";
binaryContent.MultimediaType = new LinkToMultimediaTypeData()
{
// for jpg file
IdRef = "tcm:0-2-65544"
};
multimediaComponent.BinaryContent = binaryContent;
IdentifiableObjectData savedComponent = client.Save(multimediaComponent,
new ReadOptions());
client.CheckIn(savedComponent.Id, null);
streamClient.Close();
client.Close();
Console.WriteLine(savedComponent.Id);
//}
}
I don't know why your code not working but following code is working for me
public static ComponentData GenerateMultiMediaComponent(TridionGeneration tridionGeneration, XmlData newsArticle, string componentName)
{
try
{
Dictionary<string, object> dicTridion = Common.GetTridionObject(tridionGeneration.client, ItemType.Component, tridionGeneration.Settings.ComponentFolderUri, componentName);
int objectCount = (int)dicTridion["count"];
SchemaFieldsData schemaFields = tridionGeneration.client.ReadSchemaFields(tridionGeneration.Settings.SchemaUri, true, new ReadOptions());
ComponentData componentData = (ComponentData)tridionGeneration.client.GetDefaultData(ItemType.Component, tridionGeneration.Settings.ComponentFolderUri);
if (schemaFields.Fields != null)
{
var fields = Fields.ForContentOf(schemaFields);
Helper.FillSchemaFields(tridionGeneration, fields);
componentData.Content = fields.ToString();
}
if (schemaFields.MetadataFields != null)
{
var metafields = Fields.ForMetadataOf(schemaFields, componentData);
Helper.FillSchemaFields(tridionGeneration, metafields);
componentData.Metadata = metafields.ToString();
}
componentData.Title = (objectCount == 0) ? componentName : componentName + " " + (objectCount + 1).ToString();
componentData.ComponentType = ComponentType.Multimedia;
StreamUpload2010Client streamClient = new StreamUpload2010Client();
FileStream objfilestream = new FileStream(#"[IMAGE_PATH]", FileMode.Open, FileAccess.Read);
string tempLocation = streamClient.UploadBinaryContent("images.jpg", objfilestream);
BinaryContentData binaryContent = new BinaryContentData();
binaryContent.UploadFromFile = tempLocation;
binaryContent.Filename = "[IMAGE_NAME]";
componentData.BinaryContent = binaryContent;
binaryContent.MultimediaType = new LinkToMultimediaTypeData()
{
IdRef = "tcm:0-2-65544"
};
componentData = (ComponentData)tridionGeneration.client.Create(componentData, new ReadOptions());
return componentData;
}
catch (Exception ex)
{
return null;
}
}
Here is the Helper class:
public static class Helper
{
public static void FillSchemaFields(TridionGeneration tridionGeneration, Fields fields)
{
List<XmlData> data = XmlHelper.xmlData;
var ofield = fields.GetEnumerator();
while (ofield.MoveNext())
{
Field f = ofield.Current;
FillFieldValue(tridionGeneration, fields, f, data[0]);
}
}
private static void FillFieldValue(TridionGeneration tridionGeneration, Fields fields, Field f, XmlData data)
{
if (f.Type == typeof(MultimediaLinkFieldDefinitionData))
{
fields[f.Name].Value = tridionGeneration.Settings.DefaultImageUri;
}
else if (f.Type != typeof(EmbeddedSchemaFieldDefinitionData))
{
foreach (XmlData fieldvalue in data.Attributes)
{
if (f.Type == typeof(DateFieldDefinitionData))
{
if (fieldvalue.text.ToLower() == f.Name.ToLower())
{
fields[f.Name].Value = Convert.ToDateTime(fieldvalue.value).ToString("yyyy-MM-ddTHH:mm:ss");
}
else
{
string val = FindSchemaValue(tridionGeneration, fieldvalue.Attributes, f.Name);
if (!string.IsNullOrEmpty(val))
{
fields[f.Name].Value = Convert.ToDateTime(val).ToString("yyyy-MM-ddTHH:mm:ss");
}
}
}
else
{
if (fieldvalue.text.ToLower() == f.Name.ToLower())
{
fields[f.Name].Value = System.Net.WebUtility.HtmlEncode(fieldvalue.value);
}
else
{
string val = FindSchemaValue(tridionGeneration, fieldvalue.Attributes, f.Name);
if (!string.IsNullOrEmpty(val))
{
fields[f.Name].Value = System.Net.WebUtility.HtmlEncode(val);
}
}
}
}
}
else
{
Fields fs = f.GetSubFields();
var ofield = fs.GetEnumerator();
while (ofield.MoveNext())
{
Field ff = ofield.Current;
FillFieldValue(tridionGeneration, fs, ff, data);
}
}
}
private static string FindSchemaValue(TridionGeneration tridionGeneration, List<XmlData> data, string fieldname)
{
foreach (XmlData fieldvalue in data)
{
if (fieldvalue.text.ToLower() == fieldname.ToLower())
{
return fieldvalue.value;
}
else
{
FindSchemaValue(tridionGeneration, fieldvalue.Attributes, fieldname);
}
}
return "";
}
}
and the Fields class:
public class Fields
{
private ItemFieldDefinitionData[] definitions;
private XmlNamespaceManager namespaceManager;
private XmlElement root; // the root element under which these fields live
// at any point EITHER data OR parent has a value
private SchemaFieldsData data; // the schema fields data as retrieved from the core service
private Fields parent; // the parent fields (so we're an embedded schema), where we can find the data
public Fields(SchemaFieldsData _data, ItemFieldDefinitionData[] _definitions, string _content = null, string _rootElementName = null)
{
data = _data;
definitions = _definitions;
var content = new XmlDocument();
if (!string.IsNullOrEmpty(_content))
{
content.LoadXml(_content);
}
else
{
content.AppendChild(content.CreateElement(string.IsNullOrEmpty(_rootElementName) ? _data.RootElementName : _rootElementName, _data.NamespaceUri));
}
root = content.DocumentElement;
namespaceManager = new XmlNamespaceManager(content.NameTable);
namespaceManager.AddNamespace("custom", _data.NamespaceUri);
}
public Fields(Fields _parent, ItemFieldDefinitionData[] _definitions, XmlElement _root)
{
definitions = _definitions;
parent = _parent;
root = _root;
}
public static Fields ForContentOf(SchemaFieldsData _data)
{
return new Fields(_data, _data.Fields);
}
public static Fields ForContentOf(SchemaFieldsData _data, ComponentData _component)
{
return new Fields(_data, _data.Fields, _component.Content);
}
public static Fields ForMetadataOf(SchemaFieldsData _data, RepositoryLocalObjectData _item)
{
return new Fields(_data, _data.MetadataFields, _item.Metadata, "Metadata");
}
public string NamespaceUri
{
get { return data != null ? data.NamespaceUri : parent.NamespaceUri; }
}
public XmlNamespaceManager NamespaceManager
{
get { return parent != null ? parent.namespaceManager : namespaceManager; }
}
internal IEnumerable<XmlElement> GetFieldElements(ItemFieldDefinitionData definition)
{
return root.SelectNodes("custom:" + definition.Name, NamespaceManager).OfType<XmlElement>();
}
internal XmlElement AddFieldElement(ItemFieldDefinitionData definition)
{
var newElement = root.OwnerDocument.CreateElement(definition.Name, NamespaceUri);
XmlNodeList nodes = root.SelectNodes("custom:" + definition.Name, NamespaceManager);
XmlElement referenceElement = null;
if (nodes.Count > 0)
{
referenceElement = (XmlElement)nodes[nodes.Count - 1];
}
else
{
// this is the first value for this field, find its position in the XML based on the field order in the schema
bool foundUs = false;
for (int i = definitions.Length - 1; i >= 0; i--)
{
if (!foundUs)
{
if (definitions[i].Name == definition.Name)
{
foundUs = true;
}
}
else
{
var values = GetFieldElements(definitions[i]);
if (values.Count() > 0)
{
referenceElement = values.Last();
break; // from for loop
}
}
} // for every definition in reverse order
} // no existing values found
root.InsertAfter(newElement, referenceElement); // if referenceElement is null, will insert as first child
return newElement;
}
public IEnumerator<Field> GetEnumerator()
{
return (IEnumerator<Field>)new FieldEnumerator(this, definitions);
}
public Field this[string _name]
{
get
{
var definition = definitions.First<ItemFieldDefinitionData>(ifdd => ifdd.Name == _name);
if (definition == null) throw new ArgumentOutOfRangeException("Unknown field '" + _name + "'");
return new Field(this, definition);
}
}
public override string ToString()
{
return root.OuterXml;
}
}
public class FieldEnumerator : IEnumerator<Field>
{
private Fields fields;
private ItemFieldDefinitionData[] definitions;
// Enumerators are positioned before the first element until the first MoveNext() call
int position = -1;
public FieldEnumerator(Fields _fields, ItemFieldDefinitionData[] _definitions)
{
fields = _fields;
definitions = _definitions;
}
public bool MoveNext()
{
position++;
return (position < definitions.Length);
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public Field Current
{
get
{
try
{
return new Field(fields, definitions[position]);
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public void Dispose()
{
}
}
public class Field
{
private Fields fields;
private ItemFieldDefinitionData definition;
public Field(Fields _fields, ItemFieldDefinitionData _definition)
{
fields = _fields;
definition = _definition;
}
public string Name
{
get { return definition.Name; }
}
public Type Type
{
get { return definition.GetType(); }
}
public string Value
{
get
{
return Values.Count > 0 ? Values[0] : null;
}
set
{
if (Values.Count == 0) fields.AddFieldElement(definition);
Values[0] = value;
}
}
public ValueCollection Values
{
get
{
return new ValueCollection(fields, definition);
}
}
public void AddValue(string value = null)
{
XmlElement newElement = fields.AddFieldElement(definition);
if (value != null) newElement.InnerText = value;
}
public void RemoveValue(string value)
{
var elements = fields.GetFieldElements(definition);
foreach (var element in elements)
{
if (element.InnerText == value)
{
element.ParentNode.RemoveChild(element);
}
}
}
public void RemoveValue(int i)
{
var elements = fields.GetFieldElements(definition).ToArray();
elements[i].ParentNode.RemoveChild(elements[i]);
}
public IEnumerable<Fields> SubFields
{
get
{
var embeddedFieldDefinition = definition as EmbeddedSchemaFieldDefinitionData;
if (embeddedFieldDefinition != null)
{
var elements = fields.GetFieldElements(definition);
foreach (var element in elements)
{
yield return new Fields(fields, embeddedFieldDefinition.EmbeddedFields, (XmlElement)element);
}
}
}
}
public Fields GetSubFields(int i = 0)
{
var embeddedFieldDefinition = definition as EmbeddedSchemaFieldDefinitionData;
if (embeddedFieldDefinition != null)
{
var elements = fields.GetFieldElements(definition);
if (i == 0 && !elements.Any())
{
// you can always set the first value of any field without calling AddValue, so same applies to embedded fields
AddValue();
elements = fields.GetFieldElements(definition);
}
return new Fields(fields, embeddedFieldDefinition.EmbeddedFields, elements.ToArray()[i]);
}
else
{
throw new InvalidOperationException("You can only GetSubField on an EmbeddedSchemaField");
}
}
// The subfield with the given name of this field
public Field this[string name]
{
get { return GetSubFields()[name]; }
}
// The subfields of the given value of this field
public Fields this[int i]
{
get { return GetSubFields(i); }
}
}
Can you try this?
multimediaComponent.Metadata = "<Metadata/>";

HOW to get Context of WorkflowApplication?

I'm making a Workflow designer similar to Visual Workflow Tracking*.
I would like add a new control to debug wf, but id don't know how to access to wf context
To Run WF I Use this :
WFApplication wfApp = new WorkflowApplication(act, inputs);
My idea is when i recive trace event, get context of wfApp, to get vars or arguments values.
It's posibble?
*You can donwload VisualStudioTracking Code From :
Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4
and then
:\WF_WCF_Samples\WF\Application\VisualWorkflowTracking*
Finally I solved the problem.
First I get all arguments names, and variables of workflow, from xaml.
class XamlHelper
{
private string xaml;
public XamlHelper(string xaml)
{
this.xaml = xaml;
DynamicActivity act = GetRuntimeExecutionRoot(this.xaml);
ArgumentNames = GetArgumentsNames(act);
GetVariables(act);
}
private void GetVariables(DynamicActivity act)
{
Variables = new List<string>();
InspectActivity(act);
}
private void InspectActivity(Activity root)
{
IEnumerator<Activity> activities =
WorkflowInspectionServices.GetActivities(root).GetEnumerator();
while (activities.MoveNext())
{
PropertyInfo propVars = activities.Current.GetType().GetProperties().FirstOrDefault(p => p.Name == "Variables" && p.PropertyType == typeof(Collection<Variable>));
if (propVars != null)
{
try
{
Collection<Variable> variables = (Collection<Variable>)propVars.GetValue(activities.Current, null);
variables.ToList().ForEach(v =>
{
Variables.Add(v.Name);
});
}
catch
{
}
}
InspectActivity(activities.Current);
}
}
public List<string> Variables
{
get;
private set;
}
public List<string> ArgumentNames
{
get;
private set;
}
private DynamicActivity GetRuntimeExecutionRoot(string xaml)
{
Activity root = ActivityXamlServices.Load(new StringReader(xaml));
WorkflowInspectionServices.CacheMetadata(root);
return root as DynamicActivity;
}
private List<string> GetArgumentsNames(DynamicActivity act)
{
List<string> names = new List<string>();
if (act != null)
{
act.Properties.Where(p => typeof(Argument).IsAssignableFrom(p.Type)).ToList().ForEach(dp =>
{
names.Add(dp.Name);
});
}
return names;
}
}
Second I create trace with these arguments and variable names
private static WFTrace CreateTrace(List<string> argumentNames, List<string> variablesNames)
{
WFTrace trace = new WFTrace();
trace.TrackingProfile = new TrackingProfile()
{
ImplementationVisibility = ImplementationVisibility.All,
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
// Limit workflow instance tracking records for started and completed workflow states
States = {WorkflowInstanceStates.Started, WorkflowInstanceStates.Completed },
}
}
};
trace.TrackingProfile.Queries.Add(GetActivityQueryState(argumentNames, variablesNames));
return trace;
}
And then invoke wf and add traceextension.
Adam this is the code
private TrackingQuery GetActivityQueryState(List<string> argumentNames, List<string> variablesNames)
{
ActivityStateQuery query = new ActivityStateQuery()
{
ActivityName = "*",
States = { ActivityStates.Executing, ActivityStates.Closed }
};
if (argumentNames != null)
{
argumentNames.Distinct().ToList().ForEach(arg =>
{
query.Arguments.Add(arg);
});
}
if (variablesNames != null)
{
variablesNames.Distinct().ToList().ForEach(v =>
{
query.Variables.Add(v);
});
}
return query;
}
You can use a Tracking Participants to extract the variables and arguments when the workflow is running.
I try tracking variables with this tracking participant
private static VisualTrackingParticipant VisualTracking()
{
String all = "*";
VisualTrackingParticipant simTracker = new VisualTrackingParticipant()
{
TrackingProfile = new TrackingProfile()
{
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
// Limit workflow instance tracking records for started and completed workflow states
// States = { WorkflowInstanceStates.Started, WorkflowInstanceStates.Completed },
States={all}
},
new ActivityStateQuery()
{
// Subscribe for track records from all activities for all states
ActivityName = all,
States = { all },
// Extract workflow variables and arguments as a part of the activity tracking record
// VariableName = "*" allows for extraction of all variables in the scope
// of the activity
Variables =
{
{ all }
},
Arguments={ {all}}
}
}
}
};
return simTracker;
}
and this is VisualTrackingParticipant
public class VisualTrackingParticipant : System.Activities.Tracking.TrackingParticipant
{
public event EventHandler<TrackingEventArgs> TrackingRecordReceived;
public Dictionary<string, Activity> ActivityIdToWorkflowElementMap { get; set; }
protected override void Track(TrackingRecord record, TimeSpan timeout)
{
OnTrackingRecordReceived(record, timeout);
}
//On Tracing Record Received call the TrackingRecordReceived with the record received information from the TrackingParticipant.
//We also do not worry about Expressions' tracking data
protected void OnTrackingRecordReceived(TrackingRecord record, TimeSpan timeout)
{
System.Diagnostics.Debug.WriteLine(
String.Format("Tracking Record Received: {0} with timeout: {1} seconds.", record, timeout.TotalSeconds)
);
if (TrackingRecordReceived != null)
{
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if//(
(activityStateRecord != null)
// && (!activityStateRecord.Activity.TypeName.Contains("System.Activities.Expressions")))
{
Activity act = null;
ActivityIdToWorkflowElementMap.TryGetValue(activityStateRecord.Activity.Id, out act);
TrackingRecordReceived(this, new TrackingEventArgs(
record,
timeout,
act
)
);
}
else
{
TrackingRecordReceived(this, new TrackingEventArgs(record, timeout, null));
}
}
}
}
//Custom Tracking EventArgs
public class TrackingEventArgs : EventArgs
{
public TrackingRecord Record {get; set;}
public TimeSpan Timeout {get; set;}
public Activity Activity { get; set; }
public TrackingEventArgs(TrackingRecord trackingRecord, TimeSpan timeout, Activity activity)
{
this.Record = trackingRecord;
this.Timeout = timeout;
this.Activity = activity;
}
}
if I trace this wf :
<Activity mc:Ignorable="sap" x:Class="Microsoft.Samples.Workflow" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:s1="clr-namespace:System;assembly=System" xmlns:s2="clr-namespace:System;assembly=System.Xml" xmlns:s3="clr-namespace:System;assembly=System.Core" xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities" xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System" xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel" xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core" xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:sd1="clr-namespace:System.Data;assembly=System.Data.DataSetExtensions" xmlns:sl="clr-namespace:System.Linq;assembly=System.Core" xmlns:st="clr-namespace:System.Text;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="decisionVar" Type="InArgument(x:Boolean)" />
</x:Members>
<sap:VirtualizedContainerService.HintSize>666,676</sap:VirtualizedContainerService.HintSize>
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
<Flowchart sad:XamlDebuggerXmlReader.FileName="C:\WF_WCF_Samples\WF\Application\VisualWorkflowTracking\CS\VisualWorkflowTracking\Workflow.xaml" sap:VirtualizedContainerService.HintSize="626,636" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces">
<Flowchart.Variables>
<Variable x:TypeArguments="x:String" Name="myStr" />
</Flowchart.Variables>
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">False</x:Boolean>
<av:Point x:Key="ShapeLocation">270,7.5</av:Point>
<av:Size x:Key="ShapeSize">60,75</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,82.5 300,111.5</av:PointCollection>
<x:Double x:Key="Width">611.5</x:Double>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Flowchart.StartNode>
<FlowStep x:Name="__ReferenceID0">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">179,111.5</av:Point>
<av:Size x:Key="ShapeSize">242,58</av:Size>
<av:PointCollection x:Key="ConnectorLocation">300,169.5 300,199.5 280,199.5 280,269.5</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<Assign sap:VirtualizedContainerService.HintSize="242,58">
<Assign.To>
<OutArgument x:TypeArguments="x:String">[myStr]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">PDC Rocks</InArgument>
</Assign.Value>
</Assign>
<FlowStep.Next>
<FlowStep x:Name="__ReferenceID1">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<av:Point x:Key="ShapeLocation">174.5,269.5</av:Point>
<av:Size x:Key="ShapeSize">211,61</av:Size>
<av:PointCollection x:Key="ConnectorLocation">155.33,351.361666666667 155.33,481 204.5,481</av:PointCollection>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<WriteLine sap:VirtualizedContainerService.HintSize="211,61" Text="[myStr]" />
</FlowStep>
</FlowStep.Next>
</FlowStep>
</Flowchart.StartNode>
<x:Reference>__ReferenceID0</x:Reference>
<x:Reference>__ReferenceID1</x:Reference>
</Flowchart>
</Activity>
When activitity assing close y recive this trace this args
[Arg] Value = PDC Rocks
[Arg] To = PDC Rocks
and I don't know the name of var where value is assined

Resources