how to create set of item with different template in sitecore - sitecore

i have a set of item under clarisonic catalog.I want to create the same set of items in another place.for example.I want to create same set of items under amazon with different template.
First i am getting all child items under clarisonic catalog and getting the name of those items.I am creating new items under Amazon with the names which i got it earlier with different template.
I want to create same set of items under amazon[all items under clarisonic catalog].
public void EntryPath(Item item)
{
List<string> ObjSiteNames = getMultiListValues(item, "Select Site");
GetChildrenSelectedItem(item, ObjSiteNames);
RecursiveItemCreation(item);
}
public List<string> getMultiListValues(Sitecore.Data.Items.Item item, string FieldID)
{
Sitecore.Data.Fields.MultilistField multiselect = item.Fields[FieldID];
return multiselect.GetItems().Select(a => a.Name).ToList();
}
public void GetChildrenSelectedItem(Item getChildredItem, List<string> sitesnmaes)
{
string defaultSitePath = "/sitecore/content/Administration/Sites";
masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
templateItem = masterDb.GetItem("/sitecore/templates/User Defined/SC-DW Data/Generic/Widgets/NavigationItem");
foreach (string str in sitesnmaes)
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.Append(defaultSitePath).Append("/").Append(str);
itemDesPath = masterDb.GetItem(strBuilder.ToString());
}
}
public void RecursiveItemCreation(Item Getchilds)
{
foreach (Item i in Getchilds.GetChildren())
{
i.Template = masterDb.GetItem("/sitecore/templates/User Defined/SC-DW Data/Generic/Widgets/NavigationItem").
if ((i.HasChildren))
{
}
else
{
itemDesPath.Add(i.Name, templateItem);
foreach (Item ItemDes in itemDesPath.Axes.GetDescendants())
{
if (ItemDes.Name == i.Name)
{
ItemDes.Editing.BeginEdit();
ItemDes.Fields["Datasource"].Value = i.Paths.Path;
ItemDes.Editing.EndEdit();
}
}
}
}

From what I understand you want to copy the whole tree below Clarisonic Catalog item to the Amazon node. The only difference is that the created items should use different template (/sitecore/templates/User Defined/SC-DW Data/Generic/Widgets/NavigationItem).
Code below should do the job. I haven't tested it but I'm sure you can solve all the problems you'll encounter.
public void CopyTreeStructure(Item source, Item target)
{
// find the new template you want to use
TemplateItem newTemplate = new TemplateItem(source.Database.GetItem("/sitecore/templates/User Defined/SC-DW Data/Generic/Widgets/NavigationItem"));
foreach (Item child in source.Children)
{
// create the copy of original item using new template
Item copiedItem = CreateItemUsingNewTemplate(child, target, newTemplate);
// repeat for all descendants recursively
CopyTreeStructure(child, copiedItem);
}
}
private Item CreateItemUsingNewTemplate(Item source, Item targetParent, TemplateItem templateToUse)
{
// create item
Item copiedItem = targetParent.Add(source.Name, templateToUse);
// pre-read all fields
source.Fields.ReadAll();
using (new EditContext(copiedItem))
{
// update all the fields of new item
foreach (Field field in source.Fields)
{
copiedItem[field.Name] = source[field.Value];
}
}
// return copied item so we can copy it's descendants
return copiedItem;
}

Related

Changing workflow state in Sitecore

I'm having an issue changing the workflow state for an item programmatically. The state isn't being changed no matter what I do to the field. I've tried using (new SecurityDisabler()){} and putting the item in editing mode then changing the field manually. I've noticed that the item itself has the Lock set to <r />, could this be causing an issue?
Here is some sample code of what I've tried to do:
[HttpPost]
[MultipleButton(Name = "action", Argument = "Submit")]
public ActionResult Submit(LoI model)
{
if (model.Submitted || !model.Signed)
{
return Redirect("/Profile/LoI");
}
ModifyCandidateInfo(model, true);
Session["message"] = Translate.Text("loi-submitted-message");
Session["messageClass"] = "success";
return Redirect("/Profile/LoI");
}
private static void ModifyCandidateInfo(LoI model, bool isSubmission)
{
using (new SecurityDisabler())
{
var candidateFolder = CBUtility.GetCandidateFolder();
var loi= candidateFolder.GetChildren().SingleOrDefault(loi => loi.TemplateID == LoITemplateId);
if (loi == null) return;
loi.Editing.BeginEdit();
EditFields(loi, model);
EditChildren(loi, model);
//Send emails upon submission
if (isSubmission)
{
loi.ExecuteCommand("Submit",
loi.Name + " submitted for " + model.CandidateName);
using (new SecurityDisabler())
{
loi.Editing.BeginEdit();
loi.Fields["__Workflow state"].Value = "{F352B651-341B-4CCF-89FE-BD77F5E4D540}";
loi.Editing.EndEdit();
}
}
loi.Editing.EndEdit();
}
}
I initalized the item's workflow with the following function:
public static void InitializeWorkflow(Item item, ID workflowId)
{
item.Editing.BeginEdit();
var workflow =
item.Database.WorkflowProvider.GetWorkflow(workflowId.ToString());
workflow.Start(item);
item.Editing.EndEdit();
}
The item starts at the default drafting state and executed a "Submit" command that fires off emails. Through the Sitecore UI if I hit submit it'll go to the next workflow state but not programmatically when I fire off the ExecuteCommand function. Below you'll find the ExecuteCommand function.
public static WorkflowResult ExecuteCommand(this Item item, string commandName, string comment)
{
using (new SecurityDisabler())
{
var workflow = item.Database.WorkflowProvider.GetWorkflow(item);
if (workflow == null)
{
return new WorkflowResult(false, "No workflow assigned to item");
}
var command = workflow.GetCommands(item[FieldIDs.WorkflowState])
.FirstOrDefault(c => c.DisplayName == commandName);
return command == null
? new WorkflowResult(false, "Workflow command not found")
: workflow.Execute(command.CommandID, item, comment, false);
}
}
The command fires off fine and the emails are sent but I can't figure out why the state won't change. Could someone provide me with other suggestions or a solution?
Am I reading the workflow state id correctly? I'm using the item ID for the workflow state.
I think your code is really similar to my implementation. This is my code's background.
All items have the same workflow named "WF" and it has three workflow states (Working, Awaiting Approval, and Approved). One page-item having "WF" has some rendering items and those datasource items. Suppose a content editor is ready to submit and approve the item with its related items. By hitting the "Submit" and "Approval" button in the page, all page-item's related items have the same workflow state as the page-item's one.
Most code are from Marek Musielak and this code is perfectly working in my side.
public class UpdateWorkflowState
{
// List all controls in page item
public RenderingReference[] GetListOfSublayouts(string itemId, Item targetItem)
{
RenderingReference[] renderings = null;
if (Sitecore.Data.ID.IsID(itemId))
{
renderings = targetItem.Visualization.GetRenderings(Sitecore.Context.Device, true);
}
return renderings;
}
// Return all datasource defined on one item
public IEnumerable<string> GetDatasourceValue(WorkflowPipelineArgs args, Item targetItem)
{
List<string> uniqueDatasourceValues = new List<string>();
Sitecore.Layouts.RenderingReference[] renderings = GetListOfSublayouts(targetItem.ID.ToString(), targetItem);
LayoutField layoutField = new LayoutField(targetItem.Fields[Sitecore.FieldIDs.FinalLayoutField]);
LayoutDefinition layoutDefinition = LayoutDefinition.Parse(layoutField.Value);
DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(Sitecore.Context.Device.ID.ToString());
foreach (var rendering in renderings)
{
if (!uniqueDatasourceValues.Contains(rendering.Settings.DataSource))
uniqueDatasourceValues.Add(rendering.Settings.DataSource);
}
return uniqueDatasourceValues;
}
// Check workflow state and update state
public WorkflowResult ChangeWorkflowState(Item item, ID workflowStateId)
{
using (new EditContext(item))
{
item[FieldIDs.WorkflowState] = workflowStateId.ToString();
}
Sitecore.Layouts.RenderingReference[] renderings = GetListOfSublayouts(item.ID.ToString(), item);
return new WorkflowResult(true, "OK", workflowStateId);
}
// Verify workflow state and update workflow state
public WorkflowResult ChangeWorkflowState(Item item, string workflowStateName)
{
IWorkflow workflow = item.Database.WorkflowProvider.GetWorkflow(item);
if (workflow == null)
{
return new WorkflowResult(false, "No workflow assigned to item");
}
WorkflowState newState = workflow.GetStates().FirstOrDefault(state => state.DisplayName == workflowStateName);
if (newState == null)
{
return new WorkflowResult(false, "Cannot find workflow state " + workflowStateName);
}
unlockItem(newState, item);
return ChangeWorkflowState(item, ID.Parse(newState.StateID));
}
// Unlock the item when it is on FinalState
public void unlockItem(WorkflowState newState, Item item)
{
if (newState.FinalState && item.Locking.IsLocked())
{
using (new EditContext(item, false, false))
{
item["__lock"] = "<r />";
}
}
}
}

Display items in bucket with Sitecore Data Provider

Hej Guys
I have a rather large problem, I've been tasked with creating a Custom Data Provider for extracting Stock Keeping Units(SKUs) from a SOLR database into sitecore, without actually populating the database with items.
I've created a data provider, which succesfully pulls data from the SOLR database a "creates" the items in sitecore, by using the following code:
public class SkuDataProvider : DataProvider, ISkuDataProvider
{
private readonly string _targetDatabaseName = "master";
private readonly string _idTablePrefix = "Skus";
private readonly ID _skuTemplateId = new ID("{F806B403-BDAF-4C60-959D-E706A82FC1DC}");
private readonly ID _skuRootTemplateId = new ID("{9767BC47-0A95-40E9-A2DE-3766FF241411}");
private readonly IEnumerable<SkuItemInfo> _skus;
public SkuDataProvider(/*IProductPageService productPageService*/)
{
_skus = new MockDataForSkuDataProvider().GetSimpleSkuCollection();
}
public override ItemDefinition GetItemDefinition(ID itemId, CallContext context)
{
Assert.ArgumentNotNull(itemId, "itemID");
// Retrieve the sku id from Sitecore's IDTable
var skuId = GetSkuIdFromIdTable(itemId);
if (!string.IsNullOrEmpty(skuId))
{
// Retrieve the sku data from the skus collection
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
// Ensure the sku item name is valid for the Sitecore content tree
var itemName = ItemUtil.ProposeValidItemName($"{sku.SkuId}_{sku.Name}");
// Return a Sitecore item definition for the sku using the sku template
return new ItemDefinition(itemId, itemName, ID.Parse(_skuTemplateId), ID.Null);
}
}
return null;
}
private string GetSkuIdFromIdTable(ID itemId)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemId);
if (idTableEntries.Any())
return idTableEntries[0].Key.ToString();
return null;
}
public override IDList GetChildIDs(ItemDefinition parentItem, CallContext context)
{
if (CanProcessParent(parentItem.ID))
{
var itemIdList = new IDList();
foreach (var sku in _skus)
{
var skuId = sku.SkuId;
// Retrieve the Sitecore item ID mapped to his sku
IDTableEntry mappedId = IDTable.GetID(_idTablePrefix, skuId) ??
IDTable.GetNewID(_idTablePrefix, skuId, parentItem.ID);
itemIdList.Add(mappedId.ID);
}
context.DataManager.Database.Caches.DataCache.Clear();
return itemIdList;
}
return base.GetChildIDs(parentItem, context);
}
private bool CanProcessParent(ID id)
{
var item = Factory.GetDatabase(_targetDatabaseName).Items[id];
bool canProcess = item.Paths.IsContentItem && item.TemplateID == _skuRootTemplateId && item.ID == new ID("{F37753A0-BC79-4FF7-B975-A8F142AACD76}");
return canProcess;
}
public override ID GetParentID(ItemDefinition itemDefinition, CallContext context)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
return idTableEntries.First().ParentID;
}
return base.GetParentID(itemDefinition, context);
}
public override FieldList GetItemFields(ItemDefinition itemDefinition, VersionUri version, CallContext context)
{
var fields = new FieldList();
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
if (context.DataManager.DataSource.ItemExists(itemDefinition.ID))
{
ReflectionUtil.CallMethod(typeof(ItemCache), CacheManager.GetItemCache(context.DataManager.Database), "RemoveItem", true, true, new object[] { itemDefinition.ID });
}
var template = TemplateManager.GetTemplate(_skuTemplateId, Factory.GetDatabase(_targetDatabaseName));
if (template != null)
{
var skuId = GetSkuIdFromIdTable(itemDefinition.ID);
if (!string.IsNullOrEmpty(skuId))
{
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
foreach (var field in GetDataFields(template))
{
fields.Add(field.ID, GetFieldValue(field, sku));
}
}
}
}
}
return fields;
}
protected virtual IEnumerable<TemplateField> GetDataFields(Template template)
{
return template.GetFields().Where(ItemUtil.IsDataField);
}
private string GetFieldValue(TemplateField field, SkuItemInfo sku)
{
string fieldValue = string.Empty;
switch (field.Name)
{
case "Name":
fieldValue = sku.Name;
break;
case "SkuId":
fieldValue = sku.SkuId;
break;
default:
break;
}
return fieldValue;
}
}
}
The problem emerges when accessing the Sitecore backend, where all items appears below the bucket item in a hierarchly-way.
I've checked that the Root item is set a bucket and that the template used is bucketable.
Furthermore when inserting manually in the backend, the item is correctly inserted in the bucket.
Do anyone got an idea for me, on how to fix this issue?
Best Regards
Nicolai
You need to set the Is Bucketable flag on the standard values of the template item rather than the template item itself.
Also, the way that items get "bucketed" is via events when the item is being created or saved. Sitecore then creates the bucket folders to store the items in. In your case as you have virtual items, you will need to handle their path via the data provider.
If you just want them hidden in the same way that they are in a standard bucket, then I would suggest creating a bucket folder under your SKU Root folder and using that item as the parent for all SKU virtual items. That way the bucket folder will be hidden by sitecore and you will get the same view as a standard bucket.
This is the template to use:

Programmatically add a new field in a template in sitecore

In Sitecore is it possible to programmatically add a new field in a template?
I have a template "DictionaryName", in this template I want to add a field "Newname" with its type "Single-Line Text".
I wrote and tested this code for you - it worked out perfect on my machine and created new single line field within template specified. Here is the method:
private void AddFieldToTemplate(string fieldName, string tempatePath)
{
const string templateOftemplateFieldId = "{455A3E98-A627-4B40-8035-E683A0331AC7}";
// this will do on your "master" database, consider Sitecore.Context.Database if you need "web"
var templateItem = Sitecore.Configuration.Factory.GetDatabase("master").GetItem(tempatePath);
if (templateItem != null)
{
var templateSection = templateItem.Children.FirstOrDefault(i => i.Template.Name == "Template section");
if (templateSection != null)
{
var newField = templateSection.Add(fieldName, new TemplateID(new ID(templateOftemplateFieldId)));
using (new EditContext(newField))
{
newField["Type"] = "Text"; // text stands for single-line lext field type
}
}
{
// there are no template sections here, you may need to create one. template has only inherited fields if any
}
}
}
And below is the usage - first string parameter is the name of your new field, the second is string value for template path within the database you are using:
AddFieldToTemplate("New Single Line Field", "/sitecore/templates/Sample/Sample Item");
Replace "Sample Item" template with your template path and set desired field name to add. Also do not forget usings for namespaces:
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
Hope this helps!
You can access programmatically a template from the item and then add a an item to this template. The template is a usual item childrens.
Wrote this Example for you.
Want to find out more https://doc.sitecore.com/legacy-docs/SC71/data-definition-api-cookbook-sc70-a4.pdf
public JsonResult CreateTemplate()
{
try
{
using(new SecurityDisabler())
{
///Get Database
Database master = Sitecore.Configuration.Factory.GetDatabase("master");
/// Every node in content tree ia an Item. Ex- Templates,Field, Item, etc.
/// Template: /sitecore/templates/System/Templates/Template -{AB86861A-6030-46C5-B394-E8F99E8B87DB}
var templateId = master.GetTemplate(new ID("{AB86861A-6030-46C5-B394-E8F99E8B87DB}"));
/// parentItem is the item/ Template folder where you want to create your template.
/// ParentItem: /sitecore/templates/[new folder {Guid}]
Item parentItem = master.GetItem(new ID("{3C7516ED-7E3E-4442-8124-26691599596E}"));
Item newItem = parentItem.Add("HelloTemplate", templateId);
// adding Field in Templates.
TemplateItem exampleTemplate = master.Templates[new ID(newItem.ID.ToString())];
TemplateSectionItem data = exampleTemplate?.GetSection("data");
if( data == null || data.InnerItem.Parent.ID != exampleTemplate.ID)
{
data = exampleTemplate.AddSection("Data", false);
}
TemplateFieldItem title = data?.GetField("title");
if(title == null)
{
TemplateFieldItem field = data.AddField("Title");
}
}
return Json(new { Result = "item created" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { Result = "item not created " + ex.Message+"\n"+ex.StackTrace } , JsonRequestBehavior.AllowGet);
}
}

How to enable VersionCountDisabler for Glass Mapper in Sitecore for SitecoreQuery and SitecoreChildren attributes

The glass mapper will return null object or (no items) for SitecoreQuery and SitecoreChildren attribute that are placed on the GlassModels. These attributes don't take any such parameter where I can specify them to return items if they don't exist in the the context lanaguge. The items e.g. exist in EN but don't exist in en-ES. I need to put a lot of null check in my views to avoid Null exception and makes the views or controller very messy. It is lot of boiler plate code that one has to write to make it work.
In Page Editor the SitecoreChildren returns item and content authors can create items in that langauge version by editing any field on the item. This automatically creates the item in that langauge. However the same code will fail in Preview mode as SitecoreChidren will return null and you see null pointer exception.
SitecoreQuery doesn't return any items in page editor and then Content Authors wont be able to create items in Page editor.
To make the experience good if we can pass a parameter to SiteocreQuery attribute so it disable VsersionCount and returns the items if they dont exist in that langauge.
This is actually not possible. There is an issue on GitHub which would make it easy to create a custom attribute to handle this very easy. Currently you need to create a new type mapper and copy all the code from the SitecoreQueryMapper. I have written a blog post here about how you can create a custom type mapper. You need to create the following classes (example for the SitecoreQuery).
New configuration:
public class SitecoreSharedQueryConfiguration : SitecoreQueryConfiguration
{
}
New attribute:
public class SitecoreSharedQueryAttribute : SitecoreQueryAttribute
{
public SitecoreSharedQueryAttribute(string query) : base(query)
{
}
public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
{
var config = new SitecoreSharedQueryConfiguration();
this.Configure(propertyInfo, config);
return config;
}
}
New type mapper:
public class SitecoreSharedQueryTypeMapper : SitecoreQueryMapper
{
public SitecoreSharedQueryTypeMapper(IEnumerable<ISitecoreQueryParameter> parameters)
: base(parameters)
{
}
public override object MapToProperty(AbstractDataMappingContext mappingContext)
{
var scConfig = Configuration as SitecoreQueryConfiguration;
var scContext = mappingContext as SitecoreDataMappingContext;
using (new VersionCountDisabler())
{
if (scConfig != null && scContext != null)
{
string query = this.ParseQuery(scConfig.Query, scContext.Item);
if (scConfig.PropertyInfo.PropertyType.IsGenericType)
{
Type outerType = Glass.Mapper.Sc.Utilities.GetGenericOuter(scConfig.PropertyInfo.PropertyType);
if (typeof(IEnumerable<>) == outerType)
{
Type genericType = Utilities.GetGenericArgument(scConfig.PropertyInfo.PropertyType);
Func<IEnumerable<Item>> getItems;
if (scConfig.IsRelative)
{
getItems = () =>
{
try
{
return scContext.Item.Axes.SelectItems(query);
}
catch (Exception ex)
{
throw new MapperException("Failed to perform query {0}".Formatted(query), ex);
}
};
}
else
{
getItems = () =>
{
if (scConfig.UseQueryContext)
{
var conQuery = new Query(query);
var queryContext = new QueryContext(scContext.Item.Database.DataManager);
object obj = conQuery.Execute(queryContext);
var contextArray = obj as QueryContext[];
var context = obj as QueryContext;
if (contextArray == null)
contextArray = new[] { context };
return contextArray.Select(x => scContext.Item.Database.GetItem(x.ID));
}
return scContext.Item.Database.SelectItems(query);
};
}
return Glass.Mapper.Sc.Utilities.CreateGenericType(typeof(ItemEnumerable<>), new[] { genericType }, getItems, scConfig.IsLazy, scConfig.InferType, scContext.Service);
}
throw new NotSupportedException("Generic type not supported {0}. Must be IEnumerable<>.".Formatted(outerType.FullName));
}
{
Item result;
if (scConfig.IsRelative)
{
result = scContext.Item.Axes.SelectSingleItem(query);
}
else
{
result = scContext.Item.Database.SelectSingleItem(query);
}
return scContext.Service.CreateType(scConfig.PropertyInfo.PropertyType, result, scConfig.IsLazy, scConfig.InferType, null);
}
}
}
return null;
}
public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
{
return configuration is SitecoreSharedQueryConfiguration;
}
}
And configure the new type mapper in your glass config (mapper and parameters for the constructor):
container.Register(Component.For<AbstractDataMapper>().ImplementedBy<SitecoreSharedQueryTypeMapper>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemIdNoBracketsParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemEscapedPathParameter>>().LifeStyle.Transient);
container.Register(Component.For<IEnumerable<ISitecoreQueryParameter>>().ImplementedBy<List<ItemDateNowParameter>>().LifeStyle.Transient);
You can then simply change the SitecoreQuery attribute on your model to SitecoreSharedQuery:
[SitecoreSharedQuery("./*")]
public virtual IEnumerable<YourModel> YourItems { get; set; }
For the children you could either use the shared query mapper and querying the children or create the same classes for a new SitecoreSharedChildren query.
Edit: Added bindings for IEnumerable<ISitecoreQueryParameter> as they are missing and therefor it threw an error.

RadGrid Binding to a List

XAML RadGrid
<telerik:RadGridView d:DataContext="{d:DesignInstance {x:Type local:A}}" Name="myGridView" Grid.Column="2" ItemsSource="{Binding Path=MyList}" Margin="7,7,7,2" IsFilteringAllowed="False" ShowColumnHeaders="True" AutoGenerateColumns="True" />
C# Code
Class A:INotifyPropertyChanged
{
private List<Fields> MyList;
public event PropertyChangedEventHandler PropertyChanged;
public List<Fields> _theList
{
get
{
if (MyList == null)
{
MyList = new List<Fields>();
}
return MyList;
}
set
{
if (MyList != value)
{
MyList = value;
PropertyChanged(this, new PropertyChangedEventArgs("_theList"));
}
}
}
}
When the items in MyList change dynamically, the radgridview does not update automatically, It works if I reset the Itemssource in the code:
mygridview.Itemssource = Null;
mygridview.Itemssource = MyList;
I have to reset the itemssource everytime in the code after the MyList changes. Why GridView does not update automatically when contents of MyList change?
Also, During design time it shows me appropriate column headers with no data in the columns because the list is empty. But when I run the application, column headers disappear and no data is displayed in the radgrid when contents of MyList change dynamically.
When the items in MyList change dynamically,
You're notifying when your list property changes...which doesn't cover the above scenario. In order to support what you want, I think you need a collection that supports the INotifyCollectionChanged interface.
http://msdn.microsoft.com/en-us/library/system.collections.specialized.inotifycollectionchanged.aspx
Out of the box, ObservableCollection supports this. It derives from IList<T>. So perhaps you could do:
private IList<Fields> MyList;
private IList<Fields> MyObservableList;
public event PropertyChangedEventHandler PropertyChanged;
public IList<Fields> _theList
{
get
{
if (MyObservableList == null)
{
MyObservableList = new ObservableCollection<Fields>();
}
return MyObservableList;
}
set
{
if (MyList != value)
{
MyList = value;
MyObservableList = new ObservableCollection<Fields>(MyList );
// this will throw a null reference exception if no one' is listening. You
PropertyChanged(this, new PropertyChangedEventArgs("_theList"));
}
}
}
If you can forgoe having a List<T> instance for having an ObserableCollection<T> instance, the above could be even simpler:
private ObservableCollection<Fields> MyList;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Fields> _theList
{
get
{
if (MyList== null)
{
MyList= new ObservableCollection<Fields>();
}
return MyList;
}
set
{
if (MyList != value)
{
MyList = value;
// this will throw a null reference exception if no one' is listening. You should make a method OnPropertyChanged that checks if PropertyChanged != null.
PropertyChanged(this, new PropertyChangedEventArgs("_theList"));
}
}
}
Also, as an aside, usually the private members are _camelCase and the public members are PascalCase...not sure if it's intentional.