I am developing Umbraco 7 MVC application and my requirement is to add Item inside Umbraco. Item name should be unique. For that used the below code but I am getting the error "Oops: this document is published but is not in the cache (internal error)"
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{
ContentService.Publishing += ContentService_Publishing;
}
private void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
try
{
if(newsItemExists)
{
e.Cancel = true;
}
}
catch (Exception ex)
{
e.Cancel = true;
Logger.Error(ex.ToString());
}
}
Then I tried adding code to unpublish but its not working i.e the node is getting published. Below is my code
private void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
try
{
int itemId=1234; //CurrentPublishedNodeId
if(newsItemExists)
{
IContent content = ContentService.GetById(itemId);
ContentService.UnPublish(content);
library.UpdateDocumentCache(item.Id);
}
}
catch (Exception ex)
{
e.Cancel = true;
Logger.Error(ex.ToString());
}
}
But with the above code, if you give the CurrentPublishedNodeId=2345 //someOthernodeId its unpublished correctly.
Can you please help me on this issue.
You don't have to do this, Umbraco will automatically append (1) to the name if the item already exists (so it IS unique).
If you don't want this behavior you can check in the following way:
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Publishing += ContentService_Publishing;
}
private void ContentService_Publishing(Umbraco.Core.Publishing.IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
var contentService = UmbracoContext.Current.Application.Services.ContentService;
// It's posible to batch publish items, so go through all items
// even though there might only be one in the list of PublishedEntities
foreach (var item in e.PublishedEntities)
{
var currentPage = contentService.GetById(item.Id);
// Go to the current page's parent and loop through all of it's children
// That way you can determine if any page that is on the same level as the
// page you're trying to publish has the same name
foreach (var contentItem in currentPage.Parent().Children())
{
if (string.Equals(contentItem.Name.Trim(), currentPage.Name.Trim(), StringComparison.InvariantCultureIgnoreCase))
e.Cancel = true;
}
}
}
I think your problem might be that you're not looping through all PublishedEntities but using some other way to determine the current page Id.
Note: Please please please do not use the library.UpdateDocumentCache this, there's absolutely no need, ContentService.UnPublish will take care of the cache state.
Related
I used ELAMH 1.2 to log errors in MVC 5. It work well for 404 500... HTTP errors and in controller's catch blocks.
public ActionResult Index()
{
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test"));
try
{
var a = 0;
var b = 1 / a;
}
catch(Exception e)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
}
return View();
}
i get two log for this code.
but it dosent work in a static class like below. i dont get any exception while running ErrorSignal.FromCurrentContext().Raise(e);.
public static class FileUtility
{
public static string SaveSampleFile(HttpPostedFileBase file)
{
try
{
var b = 0;
var a = 1/b;
}
catch (Exception e)
{
ErrorSignal.FromCurrentContext().Raise(e);
return null;
}
}
}
no error log nothing happen!
I have also seen this problem when calling ELMAH logger without any HttpContext in class library projects.
I used the old manual way to get around this:
Elmah.ErrorLog.GetDefault(null).Log(new Error(ex));
I have a MapControl working just creating my route. Now, I just need to figure out a way to print it out. Using the UWP printing sample, I get a black box where the control should be. The map and route are being built, just not rendered correctly in the print preview. I thought I saw a MapControl.Print... but I think that was in the Bing.Maps stuff. Any pointers would be appreciated. Thanks.
Using the UWP printing sample, I get a black box where the control should be.
It seems the MapControl can not be printed.
As a workround, we can use RenderTargetBitmap to get the image from the MapControl. That we can print the image.
Using a RenderTargetBitmap, you can accomplish scenarios such as applying image effects to a visual that originally came from a XAML UI composition, generating thumbnail images of child pages for a navigation system, or enabling the user to save parts of the UI as an image source and then share that image with other apps.
Because RenderTargetBitmap is a subclass of ImageSource, it can be used as the image source for Image elements or an ImageBrush brush.
For more info,see RenderTargetBitmap.
For example:
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(MyMap);
MyImage.Source = renderTargetBitmap;
The printing code:
public sealed partial class MainPage : Page
{
private PrintManager printmgr = PrintManager.GetForCurrentView();
private PrintDocument printDoc = null;
private PrintTask task = null;
public MainPage()
{
this.InitializeComponent();
printmgr.PrintTaskRequested += Printmgr_PrintTaskRequested;
}
private void Printmgr_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
task = args.Request.CreatePrintTask("Print", OnPrintTaskSourceRequrested);
task.Completed += PrintTask_Completed;
deferral.Complete();
}
private void PrintTask_Completed(PrintTask sender, PrintTaskCompletedEventArgs args)
{
//the PrintTask is completed
}
private async void OnPrintTaskSourceRequrested(PrintTaskSourceRequestedArgs args)
{
var def = args.GetDeferral();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
args.SetSource(printDoc?.DocumentSource);
});
def.Complete();
}
private async void appbar_Printer_Click(object sender, RoutedEventArgs e)
{
if (printDoc != null)
{
printDoc.GetPreviewPage -= OnGetPreviewPage;
printDoc.Paginate -= PrintDic_Paginate;
printDoc.AddPages -= PrintDic_AddPages;
}
this.printDoc = new PrintDocument();
printDoc.GetPreviewPage += OnGetPreviewPage;
printDoc.Paginate += PrintDic_Paginate;
printDoc.AddPages += PrintDic_AddPages;
bool showPrint = await PrintManager.ShowPrintUIAsync();
}
private void PrintDic_AddPages(object sender, AddPagesEventArgs e)
{
printDoc.AddPage(this);
printDoc.AddPagesComplete();
}
private void PrintDic_Paginate(object sender, PaginateEventArgs e)
{
PrintTaskOptions opt = task.Options;
printDoc.SetPreviewPageCount(1, PreviewPageCountType.Final);
}
private void OnGetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
printDoc.SetPreviewPage(e.PageNumber, this);
}
}
I am working with an attached behavior for logging user actions on a ScrollBar.
my code:
class ScrollBarLogBehavior : Behavior<ScrollBar>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
}
void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
...
var track = (Track)AssociatedObject.Template.FindName("PART_Track", AssociatedObject);
// ** HERE is the problem: track is null ! **
...
}
How can I detect that the template has loaded and I can find the Track?
(when I call AssociatedObject.Template.LoadContent() the result containt the requested Track, so it i a matter of timing and not a matter of wrong template or naming)
Override the method OnApplyTemplate
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var textBox = Template.FindName("PART_Textbox", this) as TextBox;
}
I did not find any good way to detect when the template was loaded. However, I did find a way to find the Track:
in OnAttached() - register to Scroll event fo the ScrollBar (this can only happen after the entire template is loaded, of course):
protected override void OnAttached()
{
base.OnAttached();
_scrollHandler = new ScrollEventHandler(AssociatedObject_Scroll);
AssociatedObject.AddHandler(ScrollBar.ScrollEvent, _scrollHandler, true);
}
When handling the Scroll event, remove registration and find the Thumb:
void AssociatedObject_Scroll(object sender, ScrollEventArgs e)
{
var track = (Track)AssociatedObject.Template.FindName("PART_Track", Associated
if (track == null)
return;
AssociatedObject.RemoveHandler(ScrollBar.ScrollEvent, _scrollHandler);
// do my work with Track
...
}
If I understand correctly, you wish to create an attached behavior that will reference a template part after the ScrollBar has been loaded.
The following should work:
internal static class ScrollBarLogBehavior
{
public static readonly DependencyProperty LogUserActionProperty = DependencyProperty.RegisterAttached(
"LogUserAction",
typeof(bool),
typeof(ScrollBarLogBehavior),
new UIPropertyMetadata(default(bool), LogUserActionChanged));
public static bool GetLogUserAction(DependencyObject obj)
{
return (bool)obj.GetValue(LogUserActionProperty);
}
public static void SetLogUserAction(DependencyObject obj, bool value)
{
obj.SetValue(LogUserActionProperty, value);
}
public static void LogUserActionChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
if (s is ScrollBar scrollBar)
{
scrollBar.Loaded += OnScrollBarLoaded;
}
}
private static void OnScrollBarLoaded(object sender, RoutedEventArgs e)
{
if (sender is ScrollBar scrollBar)
{
if (scrollBar.Template != null)
{
// I'm not sure, but the `name` in the following method call might be case sensitive.
if (scrollBar.Template.FindName("PART_Track", scrollBar) is Track track)
{
// do work with `track` here
}
}
}
}
}
where you would "attach" the behavior in your XAML with:
<ScrollBar guiControls:ScrollBarLogBehavior.LogUserAction="True">
<!-- more here -->
</ScrollBar>
BE ADVISED: this implementation completely ignores the bool value that is being set for LogUserAction
In Umbraco 6, when you create a new node, it is put at the bottom.
You have to sort it manually if you want it to be on the top.
How can you make new nodes appear on the top by default?
You could create an event handler that changes the sort order of the nodes when the new node is created. See Application startup events & event registration for more details on implementing an handler of your own.
Rough untested example which I am sure you could make more elegant but should point you in the right direction:
public class YourApplicationEventHandlerClassName : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Created += ContentServiceCreated;
}
private void ContentServiceCreated(IContentService sender, NewEventArgs<IContent> e)
{
var cs = ApplicationContext.Current.Services.ContentService;
var content = e.Entity;
var parentNode = content.Parent();
content.SortOrder = parentNode.Children().OrderBy(n => n.SortOrder).First().SortOrder - 1;
cs.Save(content);
}
}
The ContentService.Created event did not work for me. Took some battles, but in v7 of Umbraco, I've used the ContentService.Saved event instead, with some double checking on dirty properties to ensure you don't end up in a saving infinite loop:
private void ContentSaved(IContentService sender, SaveEventArgs<IContent> e)
{
foreach (var content in e.SavedEntities)
{
var dirty = (IRememberBeingDirty)content;
var isNew = dirty.WasPropertyDirty("Id");
if (!isNew) return;
var parentNode = content.Parent();
if (parentNode == null) return;
var last = parentNode.Children().OrderBy(n => n.SortOrder).FirstOrDefault();
if (last != null)
{
content.SortOrder = last.SortOrder - 1;
if (content.Published)
sender.SaveAndPublishWithStatus(content);
else
sender.Save(content);
}
}
}
public class AppStartupHandler : ApplicationEventHandler
{
protected override void ApplicationInitialized(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{
ContentService.Saved += ContentSaved;
}
}
I make a new button in Lightswitch and put this code inside to print only a single file:
partial void StampaDeposito_Execute()
{
PrintDocument printInvoice = new PrintDocument();
printInvoice.PrintPage +=
new EventHandler<PrintPageEventArgs>(printInvoice_PrintPage);
printInvoice.Print("TemplateEmail.htm");
}
void printInvoice_PrintPage(object sender, PrintPageEventArgs ev)
{
ev.HasMorePages = false;
}
but when I click the button following error appears: System.UnauthorizedAccessException: Invalid cross-thread access.
Is there a workaround to solve this?
Try this:
using Microsoft.LightSwitch.Threading
partial void StampaDeposito_Execute()
{
Dispatchers.Main.BeginInvoke(() => {
PrintDocument printInvoice = new PrintDocument();
printInvoice.PrintPage +=
new EventHandler<PrintPageEventArgs>(printInvoice_PrintPage);
printInvoice.Print("TemplateEmail.htm");
});
}
void printInvoice_PrintPage(object sender, PrintPageEventArgs ev)
{
ev.HasMorePages = false;
}
When you get an error about thread access, more often than not you can fix it by invoking the code on the main dispatcher.