When a user uses the "Insert Link" feature on the RTE to create stories, we get something like...<Item-Name-Of-Story
Instead of taking the Item name I would like to use another field called "Headline"
Does anyone know how to do this?...
Headline-Of-Story
Any help will be much appreciated. Thanks
First of all, you need need to look at this class with Reflector or DotPeek : Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm and to modify it with your own class.
You need to modify just this method,I tested and works fine :
protected override void OnOK(object sender, EventArgs args)
{
Assert.ArgumentNotNull(sender, "sender");
Assert.ArgumentNotNull((object) args, "args");
string displayName;
string text;
if (this.Tabs.Active == 0 || this.Tabs.Active == 2)
{
Item selectionItem = this.InternalLinkTreeview.GetSelectionItem();
if (selectionItem == null)
{
SheerResponse.Alert("Select an item.", new string[0]);
return;
}
else
{
displayName = selectionItem["Headline"];
if (selectionItem.Paths.IsMediaItem)
text = CustomInsertLinkForm.GetMediaUrl(selectionItem);
else if (!selectionItem.Paths.IsContentItem)
{
SheerResponse.Alert("Select either a content item or a media item.", new string[0]);
return;
}
else
{
LinkUrlOptions options = new LinkUrlOptions();
text = LinkManager.GetDynamicUrl(selectionItem, options);
}
}
}
else
{
MediaItem mediaItem = (MediaItem) this.MediaTreeview.GetSelectionItem();
if (mediaItem == null)
{
SheerResponse.Alert("Select a media item.", new string[0]);
return;
}
else
{
displayName = mediaItem.DisplayName;
text = CustomInsertLinkForm.GetMediaUrl((Item) mediaItem);
}
}
if (this.Mode == "webedit")
{
SheerResponse.SetDialogValue(StringUtil.EscapeJavascriptString(text));
base.OnOK(sender, args);
}
else
SheerResponse.Eval("scClose(" + StringUtil.EscapeJavascriptString(text) + "," + StringUtil.EscapeJavascriptString(displayName) + ")");
}
After you modify this class you need to modify next file:
\sitecore\shell\Controls\Rich Text Editor\InsertLink\InsertLink.xml where you need to change codeBeside section
<CodeBeside Type="Sitecore.Shell.Controls.RichTextEditor.InsertLink.InsertLinkForm,Sitecore.Client"/>
with something like :
<CodeBeside Type="YourNameSpace.YourInsertLinkForm,YourAssembly"/>
The simplest way around this would be to type the desired link text, then select this before clicking 'insert link' - this way your hyperlink will have the text of whatever you entered, instead of defaulting to the item name.
If you want to modify how Sitecore renders links in RTE fields, you would need to modify the <renderField> pipeline - if you search for this in the web.config, you will see the different classes involved here. Using dotPeek you can decompile the Sitecore source to see how this works. Potentially you could then create your own renderField pipeline handler to change the link rendering behaviour and then reference this new class in your web.config.
Related
So,
In my WPF application, I want my users to be able to open previews of invoices, so that they may either verify or discard them. I am letting them check rows (each row representing a invoice) in a DataGridCheckBoxColumn in my DataGrid, then clicking a button (which runs my CreateInvoicePreview() method, see bottom of post), having all of the invoice previews be opened in new windows (one window for each invoice).
Well.. What happens now, is: User checks InvoiceA and InvoiceB. Two invoices are opened, but they are the same: InvoiceC. The correct amount of invoices are always opened, but not the correct instance. If I open the temp folder specified in my file path, I see that all invoices in the datagrid has been saved: InvoiceA through InvoiceJ.
Let me take you through the code.
This is the method that creates that builds and saves the actual PDF's, which the WebView2 control uses as source, so that it can display them in-app. It is heavily abbreviated.
I have kept the structure with the nested foreach loops in case that is relevant.
public void CreatePreviewInvoice() {
/* SQL SERVER CODE
* SQL SERVER CODE
* SQL SERVER CODE */
List<PaidTrip> paidTrips = PaidTrips.ToList();
tripsGroupedByCompany = paidTrips.GroupBy(pt => pt.LicenseHolderID);
foreach (IGrouping<string, PaidTrip> companyGroup in tripsGroupedByCompany) {
/* SQL SERVER CODE
* SQL SERVER CODE
* SQL SERVER CODE */
List<LicenseHolder> licenseHolders = LicenseHolders.ToList();
IEnumerable<IGrouping<string, PaidTrip>> groupedByVehicle = companyGroup.GroupBy(n => n.VehicleID);
foreach (IGrouping<string, PaidTrip> vehicleGroup in groupedByVehicle) {
// Iterating over all data pertaining to each vehicle
foreach (PaidTrip trip in vehicleGroup) {
}
try {
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\')[1];
string fileName = $"FORHÅNDSVISNING - MÅ IKKE SENDES! {LicenseHolderID + "_" + "Faktura_" + InvoiceID}.pdf";
string filePath = $#"C:\Users\{userName}\AppData\Local\Temp\";
PdfFilePath = $"{filePath}{fileName}";
//if (LicenseHolderID == PreviewInvoiceViewModel.SelectedRow.LicenseHolderID) {
document.Save($"{PdfFilePath}");
//} else {
// return;
//}
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
}
As you see, towards the end of the method I have commented out a bit of code, which was me trying to implement a way to filter based on the checked rows only. It did not work.
This is the XAML for the WebView2:
<Wpf:WebView2
x:Name="wv_preview_invoice" Loaded="{s:Action CreatePreviewInvoice}"
Height="997" Width="702" Canvas.Left="20" Canvas.Top="71"
Source="{Binding PdfFilePath}"></Wpf:WebView2>
PdfFilePath is a property, which is referenced within the method above.
It's given a value within the method, and when Source (for the WebView2) is called, it is able to get the value from PdfFilePath, and thus display the PDF.
But as I said initially, it just creates X amount of instances/windows of the same invoice. Always the same one, because of in what order they are queried from the database.
And finally, here is the method that run when they click whichever invoices they want to preview, it's to open the new window with the WebView2 control:
public void PreviewInvoices() {
bool success = false;
foreach (PaidTrip item in PaidTrips) {
if (item.IsChecked == true) {
ShowPreviewInvoiceDetailed(item);
success = true;
}
}
if (!success) {
MessageBox.Show("You must chose an invoice to preview first.");
}
}
The method that opens the next window where the WebView2 is, looks like this:
public void ShowPreviewInvoiceDetailed() {
PreviewInvoiceDetailedViewModel viewModel = new(windowManager);
windowManager.ShowWindow(viewModel);
}
What part (or several parts) of the picture am I missing?
I managed to solve this by doing the following:
I made a property; public static string PreviewedInvoice { get; set; } in the ViewModel of the parent window. In my method that opens the child window (where the preview invoices are to be displayed) I bind it to LicenseHolderID of the rows that have a checked CheckBox, via foreach loop, like such:
public void PreviewInvoices() {
bool success = false;
foreach (PaidTrip item in PaidTrips) {
if (item.IsChecked == true) {
PreviewedInvoice = item.LicenseHolderID;
ShowPreviewInvoiceDetailed();
success = true;
}
}
if (!success) {
MessageBox.Show("You must chose an invoice to preview first.");
}
}
So now I have a way to filter only the checked rows, and make sure only the LicenseHolderID which match those in the row with a checked CheckBox, are actually saved. I updated my main method:
if (LicenseHolderID == PreviewInvoiceViewModel.PreviewedInvoice) {
document.Save($"{fullPath}");
SourcePath = fullPath;
}
And I bound SourcePath to the the source of the WebView2 in the XAML.
I feel like this is a clunky way of doing it, and I am going back and forth between layers, as a comment (since removed) mentioned.
If anyone can show me a better way, I'm all ears..
I'm new to programming and I'm trying to restrict users deleting every field for a custom barcode configuration window which looks like this:
And this is the code that we are using to delete those fields
public BarcodeViewModel(IEnumerable<BatchTypeBarcodeConfig> barcode)
{
var barcodeDescription = new StringBuilder(64);
int sequenceNumber = -1;
Fields.AddRange(
barcode
?.Where(field => field != null)
.OrderBy(field => field.StartPosition)
.Select(field =>
{
sequenceNumber++;
if (field.FieldType == FieldTypeCode.STATIC)
{
barcodeDescription.Append(field.FieldText);
}
else
{
barcodeDescription.Append("(");
barcodeDescription.Append(field.FieldName);
barcodeDescription.Append(")");
}
var newField = new BarcodeFieldViewModel(field, sequenceNumber);
newField.FieldLayoutChangedEvent += BarcodeFieldViewModel_FieldLayoutChangedEvent;
return newField;
})
?? Enumerable.Empty<BarcodeFieldViewModel>());
Description = barcodeDescription.ToString();
}
public void Delete(BarcodeFieldViewModel field)
{
field.FieldLayoutChangedEvent -= BarcodeFieldViewModel_FieldLayoutChangedEvent;
Fields.Remove(field);
UpdateFieldPositionValues();
}
by this method, users can delete every barcode config field. Is there any way to restrict users to delete every barcode field? there should be at least one barcode field in the fields window.
Any help is appreciated.
If Fields is a List<BarcodeFieldViewModel>, then you can add simple validation to your Delete method:
if (Fields.Count > 1) {
field.FieldLayoutChangedEvent -= BarcodeFieldViewModel_FieldLayoutChangedEvent;
Fields.Remove(field);
UpdateFieldPositionValues();
}
You could also use this same logic to determine if the delete button should even be visble.
I have this code where you are suppose to be able to pick specific file attributes, but for some reason it is acting really weird. Can anyone spot the error(s)?
This is in a form, I am triggering checkAttributes when a file is selected. (string)path is the path to the selected file.
private async void Dropdown_File_Attr_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
try
{
foreach (FileAttributes attr in Enum.GetValues(typeof(FileAttributes)))
if (e.ClickedItem.Text == attr.ToString() && !(bool)e.ClickedItem.Tag)
File.SetAttributes(path, File.GetAttributes(path) | attr);
else if (e.ClickedItem.Text == attr.ToString() && (bool)e.ClickedItem.Tag)
File.SetAttributes(path, File.GetAttributes(path) & ~attr);
checkAttributes(path);
await WaitX(5);
Dropdown_File.ShowDropDown();
Dropdown_File_Attr.ShowDropDown();
}
catch (Exception ex) { MessageBox.Show("An error occured:\n\n" + ex.ToString(), "Error"); }
}
public async Task WaitX(int miliseconds) { await Task.Delay(miliseconds); }
private List<string> getAttributes(string ppath)
{
List<string> result = new List<string>();
FileAttributes attrs = File.GetAttributes(ppath);
if ((attrs & FileAttributes.Archive) == FileAttributes.Archive) result.Add("Archive");
if ((attrs & FileAttributes.Compressed) == FileAttributes.Compressed) result.Add("Compressed");
// This goes on for every attribute
return result;
}
private void checkAttributes(string ppath)
{
foreach (string s in getAttributes(ppath))
foreach (ToolStripDropDownItem item in Dropdown_File_Attr.DropDownItems)
{
if (item.Text == s)
{
item.Image = Resources.check;
item.Tag = true; // isChecked
}
else
{
item.Image = Resources.cross;
item.Tag = false; // isChecked
}
}
}
Just an example:
If in the beginning only Normal is selected, and I select Hidden, Hidden is the only one with a cross. If then select ReadOnly, ReadOnly is the only one with a cross but if I check, the file is still Hidden in Windows Explorer.
I have been looking for the error hours. Can anyone please help me (I don't have a lot of experience with Enums and FileAttributes)?
you loop over all items of the dropdown, but act only on the clicked item. you have to check all of the items. and combine their values to construckt the final attribute value, or you'll never catch the automatically cleared item. or just set the one checked attribute, without combining it with the current flags of the file, id you only want to set the one anyway.
as an aside, your logic would work with multi selection, which i'd allow anyway. it makes sense to allow setting a file hidden and readonly, for example.
I have a rather simple problem (I bealive). I have this method:
void appointments_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
{
if (e.Results.Count() == 0)
{
results = "no events for the selected day";
//MessageBox.Show(results);
}
else
{
results = e.Results.Count() + " events found";
sourceItem = e.Results;
//MessageBox.Show(results);
}
}
And I can't "save" both results and sourceItem variables(which are class fields).
The Message box inside this method shows everything correct, howerver, on the outside results reverts to the default value.
The answer is simple: I didn't get how ansynch download works.
In my case I had to create a reference to my MainPage class, and bind items in appointments_SearchCompleted method.
Simple as that.
I'm trying to implement a search as you type (like in iTunes). I am using an ObjectListView. Further, I have a textbox that is used to do the search as shown below:
private void textBoxSearch_TextChanged(object sender, EventArgs e)
{
string txt = textBoxSearch.Text;
TextMatchFilter filter = null;
if (!String.IsNullOrEmpty(txt))
{
filter = TextMatchFilter.Contains(myObjectListView, txt);
}
// Setup a default renderer to draw the filter matches
if (filter == null)
myObjectListView.DefaultRenderer = null;
else
{
myObjectListView.DefaultRenderer = new HighlightTextRenderer(filter);
// Uncomment this line to see how the GDI+ rendering looks
myObjectListView.DefaultRenderer = new HighlightTextRenderer { Filter = filter, UseGdiTextRendering = false };
}
// Some lists have renderers already installed
HighlightTextRenderer highlightingRenderer = myObjectListView.GetColumn(0).Renderer as HighlightTextRenderer;
if (highlightingRenderer != null)
highlightingRenderer.Filter = filter;
myObjectListView.ModelFilter = filter;
}
Can someone figure out why this doesn't work?
The above code is meant to filter search results as the user types in the textbox (Like iTunes does, if you have ever used itunes). Apparently, up to this point, nothing happens. It seems like this code does not even execute.
Per this, the ObjectListView has a property named UseFiltering that is false by default and must be set to true to enable filtering.