I would like certain rows in an Ultragrid to be disabled depending on a boolean Sync property in the row. I have thought of two different solutions but neither have worked out.
1) Databind the Sync property to the Activation property of the row. Is this possible?
2) In an event such as the InitializeRow event of the grid find out what the Sync property is and disable the row if it is set to true. This method works apart from if some more rows are then added to the grid and the grid is then saved, the data reorders itself so that the disabled row isn't containing the right data. Therefore I need a way of knowing when this happens so that I can go through and disable the right rows again afterwards.
private void ultraGrid1_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
{
e.Row.Activation = Infragistics.Win.UltraWinGrid.Activation.AllowEdit;
if (e.Row.Cells[grdBoundGrip.DisplayLayout.Bands[0].Columns["Sync"]].Value != null && (bool)e.Row.Cells[grdBoundGrip.DisplayLayout.Bands[0].Columns["Sync"]].Value)
e.Row.Activation = Infragistics.Win.UltraWinGrid.Activation.Disabled;
}
You can also write it in your own function. I hope below solution might help you.
Create a windows form "test".. and drag/drop an "ultragird" in that windows form as shown below..
create a form load function "test_Load".. and try below code..
your rows with sync "false" is disabled..
private void test_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Address", typeof(string));
dt.Columns.Add("Sync", typeof(string));
dt.Rows.Add(new object[] {"John","United States","False" });
dt.Rows.Add(new object[] { "Xing", "China", "True" });
dt.Rows.Add(new object[] { "Ram", "Nepal", "True" });
dt.Rows.Add(new object[] { "Germany", "Thomas", "False" });
dt.Rows.Add(new object[] { "Pedrik", "Russia", "True" });
ultraGrid1.DataSource = dt;
ultraGrid1.DataBind();
DisableRowsWithSyncOff(dt.Rows.Count);
}
private void DisableRowsWithSyncOff(int _rowcount)
{
for (int i = 0; i < _rowcount; i++)
{
if (!Convert.ToBoolean(ultraGrid1.Rows[i].Cells["Sync"].Value.ToString()))
{
ultraGrid1.Rows[i].Activation = Infragistics.Win.UltraWinGrid.Activation.Disabled;
}
}
}
Related
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 />";
}
}
}
}
I've implemented an on item:saved handler per this question I posted here: Run code when Publishing Restriction is saved in Sitecore
When an author changes the publishing restrictions on a page, I iterate through each of the related components for that page, updating the publishing restrictions on each to match the page item. This works, but some pages have 150 or so components and the process of editing each is taking for ever. The result is that the UI hangs for up to 5 minutes while it runs. Not good.
I'm doing this:
compItem.Editing.BeginEdit();
compItem.Publishing.ValidFrom = pageItem.Publishing.ValidFrom;
compItem.Publishing.ValidTo = pageItem.Publishing.ValidTo;
compItem.Editing.EndEdit(true, true);
I've played around with the updateStatistics and silent arguments. If do it "silent" the UI responds, but of course it still takes forever for the update to run in the background which could cause issues, since there will be a window of time where the pub restrictions between the page and components would be out of sync.
Any thoughts on why updating 150 items is so slow? Any ways to speed it up?
Here's the full code:
public void OnItemSaved(object sender, EventArgs args)
{
Item item = Event.ExtractParameter(args, 0) as Item;
if (item == null)
return;
//if it's a page, then update the page component templates with the same publish restrictions.
if(this.HasBaseTemplate(item, GlobalId.PageBaseTemplate))
{
ItemChanges itemChanges = Event.ExtractParameter(args, 1) as ItemChanges;
if (itemChanges != null &&
(itemChanges.FieldChanges.Contains(__Validfrom) || itemChanges.FieldChanges.Contains(__Validto)))
{
foreach (Item i in this.GetPageComponents(item))
{
try
{
i.Editing.BeginEdit();
i.Publishing.ValidFrom = item.Publishing.ValidFrom;
i.Publishing.ValidTo = item.Publishing.ValidTo;
i.Editing.EndEdit(true, false);
}
catch(Exception ex)
{
i.Editing.CancelEdit();
}
}
}
}
}
protected IEnumerable<Item> GetPageComponents(Item page)
{
var links = page.Links.GetAllLinks(false, true);
var foundIds = new HashSet<ID>();
var foundComponentIds = new HashSet<ID>();
var componentIds = new List<ID> { page.ID };
using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
while (componentIds.Any())
{
var query = context.GetQueryable<LinkSearchResultItem>();
var predicate = PredicateBuilder.False<LinkSearchResultItem>();
foreach (var id in componentIds)
{
predicate = predicate.Or(sri => sri.ItemId == id);
}
query = query.Where(predicate);
var results = query.GetResults().Hits.Select(h => h.Document);
foundIds.Add(componentIds);
componentIds.Clear();
componentIds.AddRange(results
.Where(sri => (sri.Path.StartsWith("/sitecore/content/BECU/Global/Page Components/", StringComparison.InvariantCultureIgnoreCase) || sri.ItemId == page.ID) && sri.Links != null)
.SelectMany(sri => sri.Links)
.Except(foundIds));
foundComponentIds.Add(results
.Where(sri => (sri.Path.StartsWith("/sitecore/content/BECU/Global/Page Components/", StringComparison.InvariantCultureIgnoreCase)))
.Select(sri => sri.ItemId));
}
}
var database = page.Database;
return foundComponentIds.Select(id => database.GetItem(id)).Where(i => i != null);
}
I would recommend that you try wrapping your edit code with a Sitecore.Data.BulkUpdateContext as follows
...
using(new Sitecore.Data.BulkUpdateContext())
{
foreach (Item i in this.GetPageComponents(item))
{
try
{
i.Editing.BeginEdit();
i.Publishing.ValidFrom = item.Publishing.ValidFrom;
i.Publishing.ValidTo = item.Publishing.ValidTo;
i.Editing.EndEdit(true, false);
}
catch(Exception ex)
{
i.Editing.CancelEdit();
}
}
}
...
When an item is updated in Sitecore, several other background processes and events as a result of updating the item. Such an example is indexing which will slow down the update of a large number of items at once.
The BulkUpdateContext will disable most of these events and processes until the update is complete thereby hopefully speeding up the update of your items.
Note: I have yet to use this BulkUpdateContext myself but I found several posts including this Stackoverflow question where it claims that the BulkUpdateContext only improves item creation speed, not updates. However that may only apply to the particular version of Sitecore that was being used at the time. It may may no longer be the case with new versions of Sitecore (7.X and 8), so I think it is still worth a try.
I have a wpf application in which I am using xamdatagrid of infragistics 14.2 to show data.
Sometimes grid may contains more than 1000 record.In same application I have given print option to print grid data.for printing I am using Report object of Infragistics.but before printing I am generating preview of print data using xamprintpreview control.
When grid contains large data (for 1000 record) it takes 35 seconds to generate preview for 1000 records.
I am binding Datatable to xamdatagrid(so you can say every record is a type of DataRow).
To speedup the process of preview I have an idea to show only top n record of grid in preview.but I am not able to fetch top n record of grid and store them in a datatable because if I take 10 record from datatable that I have binded to grid and user has applied some filter on grid so my preview mismatch with actual grid.
So please help me to fetch tp 10 record from grid that is currently displayed and store them in
datatable.
Thanks in advance...
You have a complete working example here
The keys are:
xamDataGrid.RecordManager.GetFilteredInDataRecords() gives your the filtered records. If you have not any filter it gives you all records.
Then Take(10) will take ten as much.
And I implemented ToDataTable as an extension method to convert the records taken to a datatable.
<Window x:Class="Stackoverflow1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:igDP="http://infragistics.com/DataPresenter"
xmlns:local="clr-namespace:Stackoverflow1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<igDP:XamDataGrid x:Name="xamDataGrid" Loaded="XamDataGrid_Loaded">
<igDP:XamDataGrid.FieldLayoutSettings>
<igDP:FieldLayoutSettings FilterUIType="LabelIcons"/>
</igDP:XamDataGrid.FieldLayoutSettings>
<igDP:XamDataGrid.FieldSettings>
<igDP:FieldSettings AllowRecordFiltering="True" FilterLabelIconDropDownType="MultiSelectExcelStyle"/>
</igDP:XamDataGrid.FieldSettings>
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout>
<igDP:Field Name="Date"/>
<igDP:Field Name="Order"/>
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>
<Button x:Name="btnPrintPreview" Content="Print Preview" Height="25" Width="100" Click="btnPrintPreview_Click"/>
</Grid>
</Window>
using Infragistics.Windows.DataPresenter;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
namespace Stackoverflow1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void XamDataGrid_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<Item> list = new ObservableCollection<Item>();
for (int i = 0; i < 15; ++i)
{
list.Add(new Item { Date = DateTime.Now.AddDays(-i), Order = i});
}
xamDataGrid.DataSource = list;
}
private void btnPrintPreview_Click(object sender, RoutedEventArgs e)
{
IEnumerable<DataRecord> data = xamDataGrid.RecordManager.GetFilteredInDataRecords();
DataTable dt = data.Take(10).ToDataTable();
// DO YOUR PRINT PREVIEW
}
}
class Item
{
public DateTime Date { get; set; }
public int Order { get; set; }
}
static class Utils
{
public static DataTable ToDataTable(this IEnumerable<DataRecord> items)
{
if (items.Count() > 0)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Item));
DataTable table = new DataTable();
List<Item> list = new List<Item>();
foreach (var item in items)
{
list.Add((Item)item.DataItem);
}
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (Item item in list)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
return null;
}
}
}
In the code behind in an event handler:
private void Button_ClickEventHandler(object sender, MouseButtonEventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("Data1");
table.Columns.Add("Data2"); //etc... Add all columns necessary
var records = XamDataGridName.Records.Take(10);
foreach (var record in records)
{
var item = ((DataRecord)record).DataItem as DataType;
if (item != null)
{
table.Rows.Add(item.Data1, item.Data2);
}
}
}
Or using MVVM you can send the XamDataGrid.Records as a command parameter to a command in your view model and then loop through the data records, adding them to your data table.
I need some advice on getting values from a soap web service to display in a dropdownlist using a viewmodel, I currently receive the data for the various dropdownlists from a service class found in a service class library project (n-tier application).
The code for the dropdownlist service follows a similar format to the code below:
public IEnumerable<SelectListItem> getValuesAsSelectItems(string selected)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "Please Select", Value = string.Empty, Selected = (selected == string.Empty) });
foreach (var value in this.getValues())
{
items.Add(new SelectListItem { Text = value.Value, Value = value.Value, Selected = (selected == value.Value) });
}
return new SelectList(items, "Value", "Text");
}
I need a way of passing the values from this service to the viewmodel I have then created 7 controllers for each of the dropdownlist which will all link to partial views that I can reuse throughout the application, dropdownlists include titles, countries, states and others.
An approach you could take is to extract the drop down list values into a viewmodel of their own. So:
Step 1: Create a view model (ItemsViewModel) that encapsulates the drop down list items:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Models
{
public class DropDownListItem
{
public string Text { get; set; }
public string Value { get; set; }
}
public class ItemsViewModel
{
private readonly List<DropDownListItem> _items;
// The selected item:
public string SelectedItem { get; set; }
// The items:
public IEnumerable<SelectListItem> Items
{
get
{
var allItems = _items.Select(i => new SelectListItem
{
Value = i.Value,
Text = i.Text
});
return DefaultItem.Concat(allItems);
}
}
// Default item (i.e. the "select" text) if none selected
public IEnumerable<SelectListItem> DefaultItem
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select an item"
}, count: 1);
}
}
public ItemsViewModel()
{
}
// Constructor taking in items from service and selected item string:
public ItemsViewModel(List<DropDownListItem> items, string selected)
{
_items = items;
SelectedItem = selected;
}
}
}
Step 2: Create a partial view in the Views folder that binds to the ItemsViewModel:
#model Models.ItemsViewModel
#Html.DropDownListFor(m => m.SelectedItem, Model.Items)
Step 3: In the appropriate controller (e.g. HomeController), place the child action that pulls the data from the service, the view model and the partial view together:
[ChildActionOnly]
public ActionResult DropDownList(string type, string selected)
{
// If you need to call different services based on the type (e.g. Country), then pass through "type" and base the call on that
var items = new ItemsViewModel(
(from g in _service.getTitles() select new DropDownListItem { Text = g.Text, Value = g.Value }).ToList(),
selected);
return PartialView("DropDownPartial", items);
}
Step 4: Drop this line of code into the view where you need the drop down list:
#Html.Action("DropDownList", "Home", new { selected = "2", type = "country" })
Note that selected and type are to be determined whichever way you see fit and are optional.
Hopefully this gives you some inspiration.
CellList<Device> cellList = new CellList<Device>(new ItemCell());
where:
static class ItemCell extends AbstractCell<Device> {
#Override
public void render(Context context, Device device, SafeHtmlBuilder builder) {
if(device == null) {
return;
}
builder.appendHtmlConstant("<div>device.getId()</div>");
builder.appendHtmlConstant("<div>device.getName()</div>");
}
}
And now, I want to make an 'Edit' button, when I'll press on it - I want to see editable selected item. How can I do it? Please answer, who knows.
Use EditTextCell or ActionCell
addColumn(new EditTextCell(), "Name", new GetValue() {
#Override
public String getValue(IData contact) {
return contact.getName();
}
}, new FieldUpdater() {
#Override
public void update(int index, IData object, String value) {
try {
pandingChanges.add(new FirstNameChange(object, value));
} catch (Exception e) {
}
}
});
check this out or >THIS>
I followed the simple old way of doing this.
I used a cell list and a form attached to it. Every time you click on a row, row's data is loaded to the form. You can delete or edit the selected row via this form now.