Today I came across an idea that could come in handy in my daily work. I wanted to create an outlook add-in that shows the user-id (samAccountName) of the sender. I created a new Outlook Add-In and tried my best (I've never created one before).
This is what it looks like at the moment:
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
_explorer = Application.ActiveExplorer();
_explorer.SelectionChange += _explorer_event;
_userSearcher = new ActiveDirectoryUserSearcher();
}
private void _explorer_event() {
try {
if (Application.ActiveExplorer().Selection.Count > 0) {
var selection = Application.ActiveExplorer().Selection[1];
if (selection is Outlook.MailItem) {
var item = selection as Outlook.MailItem;
var rec = item.Application.Session.CreateRecipient(item.SenderEmailAddress);
var user = rec.AddressEntry.GetExchangeUser();
var mail = user.PrimarySmtpAddress;
var user2 = _userSearcher.First($"(mail={mail})");
//here I'd have to pot some logic to set the text of the control,
//such as "ribbon.EditBox.SetText("blabla");
}
}
}
catch (Exception e) {
Console.WriteLine(e);
throw;
}
}
Now, to show the "content" I'd like to create a new Ribbon element (maybe someone can tell if it's possible to show additional information e.g. below the message body or so?). I've added a new element to my project and called it "DisplayElement".
From different internet sources I tried to figure out how to handly those controls and added the following to the DisplayElement.cs:
public string TextBoxText { get; set; }
public DisplayElement()
{
}
public string onGetText(Office.IRibbonControl control) {
switch (control.Id.ToLower()) {
case "user-id-text":
return TextBoxText;
}
return string.Empty;
}
public void onChange(Office.IRibbonControl control, string value) {
switch (control.Id.ToLower()) {
case "user-id-text":
TextBoxText = value;
break;
}
return;
}
Unfortunately now I'm totally out. I canÄt figure out how to set the text of the editBox to the senders User-Id.
I'd need something like "_ribbon.EditBox.SetText("blabla");"
DisplayElement XAML:
<tabs>
<tab idMso="TabAddIns">
<group id="ContentGroup" label="Content">
<button id="user-id-text" label="Insert Text"
screentip="Text" onAction="OnTextButton"
supertip="Inserts text at the cursor location."/>
<editBox id="labelContent" getText="onGetText" onChange="onChange" enabled="false" screentip="User-ID" supertip="Displays the User-ID of the E-Mail Sender."/>
</group>
</tab>
</tabs>
You can get to your ribbon using Globals.Ribbons.MyRibbonName.
Be sure, that in your MyRibbonName.cs designer's file is
partial class ThisRibbonCollection
{
internal MyRibbonName MyRibbonName
{
// Getter
}
}
Then, in your ThisAddIn file, you can do following:
public partial class ThisAddIn
{
private MyRibbonName myRibb;
private Explorer exp;
private void ThisAddIn_Startup(object sender, EventArgs e)
{
myRibb = Globals.Ribbons.MyRibbonName;
exp = Application.ActiveExplorer();
exp.SelectionChange += exp_SelectionChange;
}
}
This way you can get to all properties and elements in your MyRibbonName Ribbon, including EditBox you was looking for in your Q.
Edit: I created my ribbon in the following manner:
Left mouse click on a project
Select Add > New item
Select Ribbon (Visual Designer)
In MyRibbonName.Designer.cs, partial class ThisRibbonCollection is already present.
All you need to do is add visual elements in your ribbon and implement your application's business logic. This is pretty similar to a Windows Forms developing.
Related
Pulling my hair out at the point. My Picker is showing an annoying line on the UI and/or the Picker's Title property if that's enabled. I simply want the Picker, not the stuff showing on the UI beneath it. Any idea on how to achieve this? Do I have to use a custom renderer or is there something simple I'm missing?
Note: The list is intentionally empty in the below examples.
Without the title, I click the Existing button, the line shows, click it again and the modal appears:
With the title, I click the Existing button, the line and title show, click it again and the modal appears:
Don't know why I have to click the button twice. But it's only on the initial page load. If I exit the modal and click the button again, it immediately appears, no double-click. Not sure if that's related to my original question, but thought I'd include it for additional information.
NewSubjectPage.xaml (chopped for brevity)
<ContentPage.Content>
<StackLayout x:Name="NewSubjectMainLay">
<ScrollView>
<StackLayout x:Name="NewSubjectChildLay">
<Grid>
<Button
x:Name="NewSubjectExisChrtBtn"
Clicked="NewSubjectExisChrtBtn_Clicked"
Grid.Column="2"
Text="Existing" />
</Grid>
</StackLayout>
</ScrollView>
<Picker
x:Name="NewSubjectExisChrtPck"
IsVisible="False"
ItemsSource="{Binding Charts}"
ItemDisplayBinding="{Binding Name}"
SelectedIndexChanged="NewSubjectExisChrtPck_SelectedIndexChanged"
Title="Select chart"
Unfocused="NewSubjectExisChrtPck_Unfocused"/>
</StackLayout>
</ContentPage.Content>
NewSubjectPage.xaml.cs (chopped for brevity)
public partial class NewSubjectPage : ContentPage
{
private string chartName;
private readonly NewSubjectViewModel _viewModel;
public string ChartName
{
get => chartName;
private set
{
chartName = value;
OnPropertyChanged();
}
}
public NewSubjectPage()
{
InitializeComponent();
BindingContext = _viewModel = new NewSubjectViewModel();
chartName = "";
}
private void NewSubjectExisChrtBtn_Clicked(object sender, EventArgs e)
{
_viewModel.LoadChartsCommand.Execute(null);
NewSubjectExisChrtPck.IsVisible = true;
NewSubjectExisChrtPck.Focus();
}
private void NewSubjectExisChrtPck_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
if (selectedIndex != -1)
{
ChartName = picker.Items[picker.SelectedIndex];
}
}
private void NewSubjectExisChrtPck_Unfocused(object sender, FocusEventArgs e)
{
NewSubjectExisChrtPck.IsVisible = false;
NewSubjectExisChrtPck.Unfocus();
}
}
NewSubjectViewModel.cs (chopped for brevity)
class NewSubjectViewModel : BaseViewModel
{
private ObservableCollection<Chart> charts;
public ObservableCollection<Chart> Charts
{
get { return charts; }
private set
{
charts = value;
OnPropertyChanged();
}
}
public Command LoadChartsCommand { get; set; }
public NewSubjectViewModel()
{
LoadChartsCommand =
new Command(
async () => await ExecuteLoadChartsCommand()
);
}
private async Task ExecuteLoadChartsCommand()
{
try
{
IndicatorRunning = true;
var list = await App.Database.GetChartsAsync();
Charts = new ObservableCollection<Chart>(list);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
Thanks for your help! Let me know if you need to see anything else.
First, I was not able to reproduce the issue of the modal not showing until a second click of the button. You might need to provide more code for that to happen. To even use your code sample I had to replace var list = await App.Database.GetChartsAsync(); with something else to simulate a long running task that returns an empty list. Also had to create a Chart type with a Name property. Not to mention BaseViewModel. In the future, please provide all code to reproduce the issue so there is minimal work required of the person who is trying to help you. There is concept on Stack Overflow called the MCVE (minimal, complete, verifiable example): http://stackoverflow.com/help/mcve
That said, perhaps the first click is actually focusing the emulator and making it the active app, and then the second is the first actual click on the button? This I can reproduce. IOW, if the emulator is not the foreground app, you have to click it once to make it active and then your app will handle clicks.
As for the undesirable UI, you do realize that the Picker UI is basically a clickable label that when clicked displays the actual picker modal? So when you make it visible, what you are making visible is the label UI, which has the line and the Title (if set), and when you focus that label, then the actual picker dialog is displayed. If you don't want to see the UI Label at all, then why make it visible? You can focus it without making it visible, so just remove the line NewSubjectExisChrtPck.IsVisible = true;
As a side note, when you call _viewModel.LoadChartsCommand.Execute(null); that calls an async method, var list = await App.Database.GetChartsAsync(); , so the LoadChartsCommand returns before you set the Charts property, and also then the code following the call to _viewModel.LoadChartsCommand.Execute(null); also executes before LoadChartsCommand really finishes, so you are making the picker visible and focusing it before the LoadChartsCommand finishes as well, so if you were loading actual items for the picker to display, they may not be there the first time. Maybe it's just the sample code, but I see no reason to use a command here, but rather you should just call an awaitable task. You are not binding to the LoadChartsCommand, so I see no reason for you to even use a Command in this scenario. Instead I suggest making ExecuteLoadChartsCommand public and calling it directly, e.g.:
private async void NewSubjectExisChrtBtn_Clicked(object sender, EventArgs e)
{
//_viewModel.LoadChartsCommand.Execute(null); // Returns immediately, so picker not loaded with items yet.
await _viewModel.ExecuteLoadChartsCommand(); // Waits for method to finish before before presenting the picker.
//NewSubjectExisChrtPck.IsVisible = true;
NewSubjectExisChrtPck.Focus();
}
EDITED! WORKING CODE
I have the following class:
class Medic
{
private readonly int codM;
private string numeM;
private string specialitate;
//i have a constructor and properties with get and set, correctly written
}
I added 3 textBoxes to the form to be filled, each one related to one of the class attributes.
After this i have a button, and if all 3 textbox fields are correctly completed, a new class object is created.
This object will be added to a List. And this list of objects I want to be displayed in a listBox, and be updated as I add new objects.
Also, I want to have 2 objects already in the List and displayed in the listBox as I run the program, created in the code I mean, not using the textBoxes, and the new entered objects to come after these. I barely know where to write the code to create these 2 objects, same as where is ok to create and populate the List of objects or to write the code to bind this list into the ListBox;
public partial class Form1 : Form
{
List<Medic> listaMedici = new List<Medic>();
Medic m1 = new Medic(0, "ion", "endocrinologie");
public Form1()
{
InitializeComponent();
listaMedici.Add(m1);
}
private void button1_AddObject_Click(object sender, EventArgs e)
{
if (textBox1_cod.Text == "")
errorProvider1.SetError(textBox1_cod, "Introduceti codul medicului!");
else if (textBox2_nume.Text == "")
errorProvider1.SetError(textBox2_nume, "Introduceti numele medicului");
else if (Regex.IsMatch(textBox2_nume.Text, #"^[ a-zA-Z]+$") == false)
errorProvider1.SetError(textBox2_nume, "Numele contine doar litere si spatii");
else if (textBox3_specialitate.Text == "")
errorProvider1.SetError(textBox3_specialitate, "Introduceti specialitatea medicului");
else
{
try
{
Medic medic = new Medic(Convert.ToInt32(textBox1_cod.Text), textBox2_nume.Text, textBox3_specialitate.Text);
foreach (Medic m in listaMedici)
{
if (textBox1_cod.Text == m.CodM.ToString())
{
throw new Exception("Codul contractului incalca proprietatea de unicitate. Introduceti un cod unic");
textBox1_cod.Clear();
}
}
listaMedici.Add(medic);
listBox1_medici.DataSource = new ObservableCollection<Medic>(listaMedici);
listBox1_medici.DisplayMember = nameof(Medic.NumeM);
listBox1_medici.ValueMember = nameof(Medic.CodM);
listBox1_medici.SelectedIndex = 0;
MessageBox.Show("ADDED!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
errorProvider1.Clear();
textBox1_cod.Clear();
textBox2_nume.Clear();
textBox3_specialitate.Clear();
}
}
}
private void listBox1_medici_SelectedIndexChanged(object sender, EventArgs e)
{
}
The display member should be the name of the property to display, not a string property. Reflection is used to look for a property of the name of the display member. For example if your medic.NumeM value is "Hello" WPF will look for a property named "Hello", retrieve the value of the property and display it in the listbox.
In your case the code should be: listBox1_medici.DisplayMember = "NumeM";
I have a UserControl which I am loading into a div which is inside an UpdatePanel. Here is my code for loading it:
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
And here is my code for trying to retrieve an instance of it:
controls.IDLControl IdlControl = RecursiveFindControl(this, "IDLControl") as controls.IDLControl;
private Control RecursiveFindControl(Control targetControl, string findControlId) {
if (targetControl.HasControls()) {
foreach (Control childControl in targetControl.Controls) {
if (childControl.ID == findControlId) {
return childControl;
}
RecursiveFindControl(childControl, findControlId);
}
}
return null;
}
But, all I get is null. I need help on figuring this out.
AFAIK, I need to re-add the control to the page on pre-init but it is one of the controls that can be added depending on which option is selected from a drop down list (which also is filled dynamically). I am stuck trying to figure out how to make this work.
You can try something like this to add your control back in the Page_Init based on the option selected in your DropDownList.
protected void Page_Init(Object sender, EventArgs e)
{
if (IsPostBack)
{
if (drpYourDropDown.Items.Count > 0 && drpYourDropDown.SelectedItem.Text == "yourOption")
{
AddIDLControl();
}
}
}
private void AddIDLControl()
{
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
}
I am customizing the ribbon toolbar and adding a button to it. Whenever I click on that button, it will open a aspx page allows authors to select some data, which gets appended to the existing RTF field content.
But when popup is opened it is having the below error in the browser (Internet Explorer).
I am inheriting Tridion page in the code behind file. When I try to use Response.Write() functions it is giving error like "Expected ;". Please tell me the reason why it is giving the error like that? Early responce is appreciated. Thanks in advance.
PFB the related code:
Aspx page code behind file contents:
namespace ButtonReference.Popups
{
[ControlResourcesDependency(new Type[] { typeof(Popup), typeof(Tridion.Web.UI.Controls.Button), typeof(Stack), typeof(Dropdown), typeof(List) })]
[ControlResources("RTFExtensions.ButtonReferenece")]
public partial class PopupReference : TridionPage
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
TridionManager tm = new TridionManager();
tm.Editor = "PowerTools";
System.Web.UI.HtmlControls.HtmlGenericControl dep = new System.Web.UI.HtmlControls.HtmlGenericControl("dependency");
dep.InnerText = "Tridion.Web.UI.Editors.CME";
tm.dependencies.Add(dep);
System.Web.UI.HtmlControls.HtmlGenericControl dep2 = new System.Web.UI.HtmlControls.HtmlGenericControl("dependency");
dep2.InnerText = "Tridion.Web.UI.Editors.CME.commands";
tm.dependencies.Add(dep2);
//Add them to the Head section
this.Header.Controls.Add(tm); //At(0, tm);
}
protected void Page_Load(object sender, EventArgs e)
{
mySession = new Tridion.ContentManager.Session(#"");
if (!Page.IsPostBack)
{
try
{
if (true)
{}
else
{
//Response.Write("Invalid schema chosen");
return;
}
}
}
}
}
Small remark: since your page will be used as a simple popup, you don't need to load Domain Model related JavaScript stuff. Not loading it will reduce the load time for your page. To do that you need to set IsStandAloneView Tridion Manager property to false:
tm.IsStandAloneView = false;
I'm creating a custom web user control in c#. It is intended to interact with a permission hierarchy. We have different "sites" and each site has many "apps" and each app has many "permissions"
So, We have a TabPanel that loads a tab for each site. Then in each tab we have a TreeView where the parent nodes are the apps and the inner nodes are the permissions.
The Permissions show check boxes based on some criteria and are checked based on whether or not the HasPermission function returns true.
All of this code works...but only for the first user selected. For any subsequent user chosen, a step through the debugger shows all the correct logic being executed, but the page displays the same information as that of the first user selected.
So basically, it's saving the display somewhere...and I'm at a loss to find out where.
public partial class Permissions : System.Web.UI.UserControl
{
string _NTLogin;
CoreUser _User;
bool _IsAdmin;
public string NTLogin
{
get
{
return _NTLogin;
}
set
{
ViewState["NTLogin"] = value;
_NTLogin = value;
}
}
public bool IsAdmin
{
get
{
return _IsAdmin;
}
set
{
ViewState["IsAdmin"] = value;
_IsAdmin = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
public void LoadTabs()
{
string [] sites = MISCore.BusinessLayer.CorePermission.GetSites();
foreach (string site in sites)
{
TabPanel tp = new TabPanel();
tp.HeaderText = site;
TabContainer1.Tabs.Add(tp);
}
}
public void LoadTrees()
{
if(_User == null)
return;
TabPanelCollection tabs = TabContainer1.Tabs;
foreach (TabPanel tab in tabs)
{
string site = tab.HeaderText;
string[] apps = MISCore.BusinessLayer.CorePermission.GetApplications(site);
TreeView tv1 = new TreeView();
tv1.EnableViewState = false;
foreach (string app in apps)
{
TreeNode tn1 = new TreeNode(app);
tn1.SelectAction = TreeNodeSelectAction.None;
string[] perms = MISCore.BusinessLayer.CorePermission.GetPermissions(site, app);
foreach (string perm in perms)
{
TreeNode tcn1 = new TreeNode(perm);
tcn1.SelectAction = TreeNodeSelectAction.None;
if (IsAdmin || _User.Manager.HasPermission(site, app, perm))
{
tcn1.ShowCheckBox = true;
if (_User.HasPermission(site, app, perm))
{
tcn1.Checked = true;
}
else
{
tcn1.Checked = false;
}
}
else
{
tcn1.ShowCheckBox = false;
}
tn1.ChildNodes.Add(tcn1);
}
tv1.Nodes.Add(tn1);
}
tab.Controls.Add(tv1);
}
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
_NTLogin = (string)ViewState["NTLogin"];
_IsAdmin = (bool)ViewState["IsAdmin"];
if(_NTLogin != null)
_User = new CoreUser(_NTLogin);
TabContainer1.Tabs.Clear();
LoadTabs();
LoadTrees();
}
}
[UPDATE]
I iterate through the treeview after all the above code, it correctly stores their correct status. This is an issue with displaying. I can successfully change any other property, tooltip, text, etc to display their state, but the checkboxes are not updating...
I would use Fiddler to see who is caching the results. By looking at the requests you'll be able to tell if it's the browser or the server causing the problem.
Or if its okay with your client, you can put in a small link button that says refresh, and either you or the user can force this refresh treeview method, whenever required.
Should be pretty simple, in the paramters for the tab just add EnableViewState = false. Let me know if this works for you.