MvxAutoCompleteTextView does not show dropdown list - mvvmcross

When I enter "aa" in MvxAutoCompleteTextView. No dropdown list shown.
Anyone knows how to use MvxAutoCompleteTextView? No example in Mvvmcross NPlus1Days and Tutorials.Thanks
Layout
<MvxAutoCompleteTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="Text SearchKey; ItemsSource ListAddresses; PartialText LabelTitle; SelectedObject Address" />
ViewModel
private string _SearchKey;
public string SearchKey
{
get { return _SearchKey; }
set { _SearchKey = value; RaisePropertyChanged(() => SearchKey); }
}
private List<string> _ListAddresses = new List<string>(){ "aa", "bb", "cc" };
public List<string> ListAddresses
{
get { return _ListAddresses; }
set { _ListAddresses = value; RaisePropertyChanged(() => ListAddresses); }
}
private string _LabelTitle;
public string LabelTitle
{
get { return _LabelTitle; }
set { _LabelTitle = value; RaisePropertyChanged(() => LabelTitle); }
}
private string _Address;
public string Address
{
get { return _Address; }
set { _Address = value; RaisePropertyChanged(() => Address); }
}

Here is an example that works:
https://github.com/JimWilcox3/MvxAutoCompleteTest

I had trouble with this control as well and Jim's example helped a lot. This answer warns against binding Text and I think that has some merit purely because for me the control was half working. When binding to Text the list view would appear but I could never bind SelectedObject or PartialText. I noticed I was receiving the following bind error:
Error - autoComplete is null in MvxAutoCompleteTextViewPartialTextTargetBinding
The simple fix for me was to change
<MvxAutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />
To
<Mvx.MvxAutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />

Related

How can I Enable/Disable a tab in AppShell via binding ? It does not work for me, I am doing something wrong

Please send me in the right direction here - I'm really confused.
See, I have this App.Shell:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="ExpensesMobile.AppShell"
x:DataType="Login_VM:Login_VM"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Approvals="clr-namespace:ExpensesMobile.View.Approvals"
xmlns:Settings="clr-namespace:ExpensesMobile.View.AppSettings"
xmlns:Login_VM="clr-namespace:ExpensesMobile.ViewModel.Login"
xmlns:Login="clr-namespace:ExpensesMobile.View.Login"
xmlns:Globals="clr-namespace:ExpensesMobile"
xmlns:ExpenseReports="clr-namespace:ExpensesMobile.View.ExpenseReports"
xmlns:res="clr-namespace:ExpensesMobile.Resources.Strings"
Title="{x:Static res:AppRes.ExpenseReports}"
Shell.FlyoutBehavior="Disabled">
<Shell.Items>
<ShellContent x:Name="Login" ContentTemplate="{DataTemplate Login:Login}" Route="Login" Shell.FlyoutBehavior="Disabled" Shell.NavBarIsVisible="False" ></ShellContent>
</Shell.Items>
<TabBar Route="Login">
<ShellContent ContentTemplate="{DataTemplate Login:Login}" Shell.FlyoutBehavior="Disabled" Shell.NavBarIsVisible="False" ></ShellContent>
</TabBar>
<TabBar x:Name="MyTabBar" Shell.NavBarHasShadow="true" Route="Home">
<Tab
x:Name="tabExpenseReports"
Title="{x:Static res:AppRes.ExpenseReports}"
Icon="ExpenseReports"
Shell.BackgroundColor="#001933"
Shell.ForegroundColor="#AB1300">
<ShellContent
x:Name="Pending"
ContentTemplate="{DataTemplate ExpenseReports:Pending}"
Route="Pending"
Title="{x:Static res:AppRes.Pending}"
Icon="pending.svg"
Shell.NavBarIsVisible="False">
</ShellContent>
<ShellContent
x:Name="Finalized"
ContentTemplate="{DataTemplate ExpenseReports:Finalized}"
Route="Finalized"
Title="{x:Static res:AppRes.Finalized}"
Icon="finalized.svg"
Shell.NavBarIsVisible="False">
</ShellContent>
</Tab>
<Tab
x:Name="tabApprovals"
Title="{x:Static res:AppRes.Approvals}"
Icon="approvals"
IsEnabled="{Binding TabApprovalsIsEnabled}"
Shell.BackgroundColor="#AB1300"
Shell.ForegroundColor="#001933">
<ShellContent
x:Name="Approvals"
ContentTemplate="{DataTemplate Approvals:Approvals}"
Shell.NavBarIsVisible="False"
Route="Approvals"
Title="{x:Static res:AppRes.Approvals}"
Icon="approvals.svg">
</ShellContent>
<ShellContent
x:Name="Approved"
ContentTemplate="{DataTemplate ExpenseReports:Approved}"
Shell.NavBarIsVisible="False"
Route="Approved"
Title="{x:Static res:AppRes.Approved}"
Icon="approved.svg">
</ShellContent>
</Tab>
<Tab
Title="{x:Static res:AppRes.Settings}"
Icon="settings" Shell.BackgroundColor="#193300"
x:Name="tabSettings">
<ShellContent
ContentTemplate="{DataTemplate Settings:Settings}"
Route="Settings" />
</Tab>
</TabBar>
</Shell>
In the Login page I decide whether the logged-in user is an admin or not. If he isn't, then he shouldn't have access to the tab "Approvals".
I have tried in several ways to make the tab disabled in this case. This is what I have right now:
In the class "Globals" I have this (I have them in the Globals class because I will need to refer to these values across the application):
using ExpensesMobile.Model;
namespace ExpensesMobile
{
public static class Globals
{
public static ExpensesMobileDB ExpensesMobileDB;
public static LoginStatus loginStatus;
public enum LoginStatus
{
loginRefused,
loginAcceptedAdmin,
loginAcceptedRegularUser
}
}
}
In Login_VM I have this code:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ExpensesMobile.Resources.Strings;
using ExpensesMobile.Services;
using ExpensesMobile.Utils;
using ExpensesMobile.View.ExpenseReports;
using System.Diagnostics;
using static ExpensesMobile.Globals;
namespace ExpensesMobile.ViewModel.Login
{
[QueryProperty(nameof(Login), "Login")]
public partial class Login_VM : Base_VM
{
public readonly LoginService loginService;
private readonly IConnectivity connectivity;
[ObservableProperty]
private string password;
[ObservableProperty]
private bool tabApprovalsIsEnabled = false;
[ObservableProperty]
private string username;
public Login_VM(LoginService loginService, IConnectivity connectivity)
{
this.loginService = loginService;
this.connectivity = connectivity;
//TEMP CODE - DEBUG
username = ".....";
password = ".....";
}
private static async Task ShowToast(LoginStatus loginStatus)
{
string text;
if (loginStatus == LoginStatus.loginAcceptedAdmin)
text = AppRes.LoginConfirmationManager;
else
text = AppRes.LoginConfirmationUser;
await Utils.Utils.ShowToast(text);
}
[RelayCommand]
private async Task LoginAsync()
{
if (IsBusy)
{
return;
}
try
{
if (connectivity.NetworkAccess != NetworkAccess.Internet)
{
await Shell.Current.DisplayAlert(AppRes.MsgConnectivity1, AppRes.MsgConnectivity2, "OK"); //No connectivity, Please check your internet connection and then try again;
return;
}
IsBusy = true;
LoginStatus loginStatus = LoginService.Login(username, password);
if (loginStatus == LoginStatus.loginAcceptedAdmin)
{
TabApprovalsIsEnabled = true;
await ShowToast(loginStatus);
await Shell.Current.GoToAsync($"//{nameof(Pending)}");
}
else if (LoginService.Login(username, password) == LoginStatus.loginAcceptedRegularUser)
{
TabApprovalsIsEnabled = false;
await ShowToast(loginStatus);
await Shell.Current.GoToAsync($"//{nameof(Pending)}");
}
else if (LoginService.Login(username, password) == LoginStatus.loginRefused)
{
await Shell.Current.DisplayAlert(AppRes.Login, AppRes.LoginWrongUsernameOrPass, "OK"); //Wrong username and/or password !
}
Globals.loginStatus = loginStatus;
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to login: {ex.Message}");
ErrorHandling.HandleError(ex);
}
finally
{
IsBusy = false;
}
}
}
}
If I login as a regular user, the line 'tabApprovalsIsEnabled = false;' executes.
I have added this line because I wanted App.Shell to bind to Login_VM and not to Globals directly (that is a regular class, and has no knowledge of ObservableProperties).
However, although the tab Approvals has the xaml 'IsEnabled="{Binding TabApprovalsIsEnabled}"', this is not taken into consideration and my tab remains enabled.
Obviously I am missing something, and probably I am ignorant enough of the sequence of operations in MAUI - probably the code above executes and sets the property "tabApprovalsIsEnabled" to false AFTER the binding in AppShell has been done, I don't know....
How could I solve this problem, please ?
Thank you very much,
Alex.
You should reset the value of property TabApprovalsIsEnabled not tabApprovalsIsEnabled .
Please refer to the following code:
[RelayCommand]
private async Task LoginAsync()
{
// other code
try
{
// other code
LoginStatus loginStatus = LoginService.Login(username, password);
if (loginStatus == LoginStatus.loginAcceptedAdmin)
{
// replace `tabApprovalsIsEnabled` with `TabApprovalsIsEnabled`
//tabApprovalsIsEnabled = true;
TabApprovalsIsEnabled = true;
//........
}
else if (LoginService.Login(username, password) == LoginStatus.loginAcceptedRegularUser)
{
// replace `tabApprovalsIsEnabled` with `TabApprovalsIsEnabled`
// tabApprovalsIsEnabled = false;
TabApprovalsIsEnabled = true;
}
else if (LoginService.Login(username, password) == LoginStatus.loginRefused)
{
//Wrong username and/or password !
await Shell.Current.DisplayAlert(AppRes.Login, AppRes.LoginWrongUsernameOrPass, "OK");
}
Globals.loginStatus = loginStatus;
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to login: {ex.Message}");
ErrorHandling.HandleError(ex);
}
finally
{
IsBusy = false;
}
}
Note:
We need set BindingContext for AppShell.xaml.cs. Then if we change the value of property TabApprovalsIsEnabled of the current ViewModel, the UI could refresh automatically.
public partial class AppShell : Shell
{
Login_VM _VM;
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute("DetailPage", typeof(DetailPage));
_VM = new Login_VM();
this.BindingContext = _VM;
}
[Obsolete]
protected override void OnAppearing()
{
base.OnAppearing();
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
_VM.TabApprovalsIsEnabled = false;
return false;
});
}
}

primefaces org.primefaces.component.diagram override

I have a problem with org.primefaces.component.diagram, i want to add an action when click on any overlay or connector, i make this using jquery, but the problem is that there is no identifier for the connection, after search i was able to get the ids of the 2 end points of the connection but if there is many connection between the same points then i cannot distinguish between them, i tried to override the diagram and add "connectionId" attribute on the connection but i got an exception in the front end :
Uncaught ReferenceError: connectionId590236 is not defined at eval (eval at (jquery.js.xhtml?ln=primefaces&v=5.2:14), :1:1488)
screenshot
The closet solution would be is to use setId on Element in the DefaultDiagramModel creation.
An example would be as the following:
Element elementA = new Element("A", "20em", "6em");
elementA.setId("element-a");
Element elementB = new Element("B", "10em", "18em");
elementB.setId("element-b");
Element elementC = new Element("C", "40em", "18em");
elementC.setId("element-c");
...
Since PrimeFaces doesn't provide the control you are searching for, and the original component comes from jsPlumb, you may rely on that to achieve what you are looking for.
First make sure that the <p:diagram> has a widgetVar value, es. diagramWV
An example would be the following:
$(document).ready(function () {
//timeout makes sure the component is initialized
setTimeout(function () {
for (var key in PF('diagramWV').canvas.getAllConnections()) {
if (PF('diagramWV').canvas.getAllConnections().hasOwnProperty(key)) {
//Elemenets Events
// on source just once
$(PF('diagramWV').canvas.getAllConnections()[key].source).off('click').on('click', function () {
console.log($(this).attr('id'))
});
// on target just once
$(PF('diagramWV').canvas.getAllConnections()[key].target).off('click').on('click', function () {
console.log($(this).attr('id'))
});
//Connection Event
PF('diagramWV').canvas.getAllConnections()[key].bind("click", function (conn) {
console.log("source " + conn.sourceId);
console.log("target " + conn.targetId);
});
}
}
}, 500);
});
Note: The canvas property of the widgetVar is the current instance of jsPlumbInstance
Here's an online demo, and a small working example on github.
finally i found an acceptable solution :
-> add an label overlay on the connection and set the identifier on it.
org.primefaces.model.diagram.Connection conn = new org.primefaces.model.diagram.Connection(
EndPointA, EndPointB);
LabelOverlay labelOverlay = new LabelOverlay(connection.getId(), "labelOverlayClass", 0.3);
conn.getOverlays().add(labelOverlay);
-> then add JS function to handle on dbclick action on the connection and get the id from its related overlay using the classes "._jsPlumb_overlay" and "._jsPlumb_hover"
<p:remoteCommand name="connectionClicked"
actionListener="#{yourBean.onConnectionDoubleClick}" />
<script type="text/javascript">
var connectionId;
$('._jsPlumb_connector').on('dblclick', function(e) {
$('._jsPlumb_overlay._jsPlumb_hover').each(function() {
connectionId = $(this).text();
});
connectionClicked([ { name : 'connectionId', value : connectionId } ]);
});
});
</script>
-> finally in the bean you extract the id and do whatever you want
public void onConnectionDoubleClick() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
String connectionId = params.get("connectionId");
if(StringUtils.isBlank(connectionId))
return;
.........
I was able to add a click event to Overlay by extending the primefaces Overlay class. If you make a change to the toJS() class (taking heavy inspiration from the Primefaces LabelOverLay) then you can write your own overlay with the jsplumb overlay constructor. Here's my implementation of a ClickableLabelOverlay.
public class ClickableLabelOverlay implements Overlay {
private String label;
private String styleClass;
private double location = 0.5;
private String onClick;
public ClickableLabelOverlay() {
}
public ClickableLabelOverlay(String label) {
this.label = label;
}
public ClickableLabelOverlay(String label, String styleClass, double location, String onClick) {
this(label);
this.styleClass = styleClass;
this.location = location;
this.onClick = onClick;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getStyleClass() {
return styleClass;
}
public void setStyleClass(String styleClass) {
this.styleClass = styleClass;
}
public double getLocation() {
return location;
}
public void setLocation(double location) {
this.location = location;
}
public String getOnClick() {
return onClick;
}
public void setOnClick(String onClick) {
this.onClick = onClick;
}
public String getType() {
return "Label";
}
public String toJS(StringBuilder sb) {
sb.append("['Label',{label:'").append(label).append("'");
if(styleClass != null) sb.append(",cssClass:'").append(styleClass).append("'");
if(location != 0.5) sb.append(",location:").append(location);
if(onClick != null) sb.append(",events:{click:function(labelOverlay, originalEvent){").append(onClick).append("}}");
sb.append("}]");
return sb.toString();
}
}
Put any javascript you want to execute inside of the onClick variable and it'll run when you click on the overlay. For convenience I added it to the set of default overlays for my diagram.
diagram.getDefaultConnectionOverlays().add(new ClickableLabelOverlay(...)

Passing binded item to MvxCommand

Considering the following code:
<Mvx.MvxListView
android:id="#+id/items_list"
style="#style/ListNoDividers"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_above="#+id/footer_panel"
android:layout_below="#+id/intro_text"
local:MvxBind="ItemsSource Items;ItemClick DoItCommand"
local:MvxItemTemplate="#layout/item_template" />
I know that when I tap in item in the list, the DoItCommand will be invoked and the binded item will be past as a command parameter.
How can I use the same in a non MvxListView, like on this code snippet:
<LinearLayout
android:id="#+id/item1"
style="#style/ItemStyle"
local:MvxBind="Click DoItCommand, CommandParameter=PropertyInViewModel"
android:layout_marginBottom="#dimen/HalfDefaultInnerMargin" />
<LinearLayout
android:id="#+id/item1"
style="#style/ItemStyle"
local:MvxBind="Click DoItCommand, CommandParameter=OtherPropertyInViewModel"
android:layout_marginBottom="#dimen/HalfDefaultInnerMargin" />
Bottom line is that I need to pass a property value to DoItCommand using the command parameter.
As pointed out in the comments, using a similar approach to this, solves the issue!
public class MyLinearLayout : LinearLayout
{
public HhLinearLayout(Context context, IAttributeSet attrs)
: base(context, attrs)
{
Click += LinearLayoutClick;
}
public ICommand Command { get; set; }
public object CommandParameter { get; set; }
private void LinearLayoutClick(object sender, EventArgs e)
{
var command = Command;
var commandParameter = CommandParameter;
if (command == null || !command.CanExecute(commandParameter))
{
return;
}
command.Execute(commandParameter);
}
}

mvvmcross keep program settings using file plugin and json serialize/deserialize

I'm trying to use the fileplugin and json serializer to do this.
I have the following DcsSetup class, in the core project.
For now I'm working with droid. I can't seem to save the file. The json serialize is ok. The WriteFile seems ok, but next time I try to read the file using TryReadTextFile it fails.
I can't find the file on the device, so I think the WriteFile stuff is wrong.
What is the correct way to save and read my Settings class on Android?
public class DcsSetup
{
public class Settings
{
//Server
public string Server;
public int Port;
public int Device;
public string EncodingFromClient;
public string EncodingToClient;
public int FontCorrectionPixelsWidth; //Pixels to add or subtract i Y dimension to get the right font size
public int FontCorrectionPixelsHeight; //Pixels to add or subtract i Y dimension to get the right font size
public float XPct;//Pct to add to vertical placement of textBox and Buttons.
public float YPct;//Pct to add to horisontal placement of textBox and Buttons.
public float SizePct;//Pct to add to horisontal size of textBox and Buttons.
public bool FullScreen;
public bool DontSleep;
//Diverse
public bool AutoSendEnter;
}
public Settings Setting;
public DcsSetup()
{
var setupFound=true;
var fileService = Mvx.Resolve<IMvxFileStore>();
var jsonConvert = Mvx.Resolve<IMvxJsonConverter>();
var path = fileService.PathCombine("Setting", "Settings.txt");
Setting = new Settings();
try {
string settingFile;
if (fileService.TryReadTextFile(path, out settingFile)){
Setting = jsonConvert.DeserializeObject<Settings>(settingFile);
} else{
setupFound = false;
}
}
catch(Exception e) {
AppTrace.Error("Failed to read settings: {0}", e.Message);
setupFound=false;
}
if(setupFound==false){
Setting.Server = "192.168.1.100";
Setting.Port = 1650;
Setting.Device = 1;
Setting.EncodingFromClient = "CP1252";
Setting.EncodingToClient = "CP1252";
Setting.FontCorrectionPixelsWidth = 0;
Setting.FontCorrectionPixelsHeight = 0;
Setting.XPct = 97.0f;
Setting.YPct = 100.0f;
Setting.SizePct = 98.0f;
Setting.FullScreen = false;
Setting.DontSleep = true;
Setting.AutoSendEnter = true;
try {
//json
var json = jsonConvert.SerializeObject(Setting);
fileService.EnsureFolderExists("Setting");
fileService.WriteFile(path, json);
}
catch (Exception e) {
AppTrace.Error("Failed to save settings: {0}", e.Message);
}
}
}
}
}
I just created a project in VS2012 using the 3.1.1-beta2 packages for MvvmCross
I then added the File and Json plugin packages
I changed the core FirstViewModel to:
public class FirstViewModel
: MvxViewModel
{
private readonly IMvxFileStore _fileStore;
private readonly IMvxJsonConverter _jsonConverter;
private readonly string _filePath;
public class ToStore
{
public string Foo { get; set; }
}
public ICommand SaveCommand
{
get
{
return new MvxCommand(() =>
{
var toStore = new ToStore() {Foo = Hello};
var json = _jsonConverter.SerializeObject(toStore);
_fileStore.WriteFile(_filePath, json);
});
}
}
public ICommand LoadCommand
{
get
{
return new MvxCommand(() =>
{
string txt;
if (_fileStore.TryReadTextFile(_filePath, out txt))
{
Mvx.Trace("Loaded {0}", txt);
var stored = _jsonConverter.DeserializeObject<ToStore>(txt);
Hello = stored.Foo;
}
});
}
}
private string _hello = "Hello MvvmCross";
public FirstViewModel(IMvxFileStore fileStore, IMvxJsonConverter jsonConverter)
{
_fileStore = fileStore;
_jsonConverter = jsonConverter;
_filePath = _fileStore.PathCombine("SubDir", "MyFile.txt");
_fileStore.EnsureFolderExists("SubDir");
}
public string Hello
{
get { return _hello; }
set { _hello = value; RaisePropertyChanged(() => Hello); }
}
}
I called this from a test Android UI:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxBind="Text Hello"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Load"
local:MvxBind="Click LoadCommand"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
android:text="Save"
local:MvxBind="Click SaveCommand"
/>
</LinearLayout>
This seemed to work OK - it saved and loaded the JSON fine within and between test runs.
Based on this, my only guess is whether you are redeploying the app between runs - if you do this and you don't have MonoDroid's Preserve application data/cache on device between deploys checked, then you won't see the settings preserved.

ConfigurationSection with nested ConfigurationElementCollections

Hopefully, I can present this problem to the brain trust of this site and someone will see my mistake.
I am working on a project where email text needs to be "mail merged" with information found in the properties of various internal classes. A typical symbol found in the email text might look like "{member name}, {mobile phone}, etc."
I would like to define the symbols and the classes they are found in using a ConfigurationSection in web.config. Here is my proposed configuration section:
<EmailSymbols>
<SymbolClasses>
<SymbolClass name="OHMember">
<Symbol name="Member Name" template="{0} {1}">
<add index="0" value="SMFirstName" />
<add index="1" value="SMLastName" />
</Symbol>
<Symbol name="Phone" template="{0}">
<add index="0" value="SMPhone" />
</Symbol>
</SymbolClass>
<SymbolClass name="Form">
<Symbol name="Contact Name" dataname="ContactName" />
</SymbolClass>
</SymbolClasses>
</EmailSymbols>
...and the code that I am trying to parse it with:
public class EmailSymbols : ConfigurationSection {
[ConfigurationProperty("SymbolClasses", IsRequired = true)]
public SymbolClassCollection SymbolClasses {
get {
return this["SymbolClasses"] as SymbolClassCollection;
}
}
}
[ConfigurationCollection(typeof(SymbolClass), AddItemName = "SymbolClass")]
public class SymbolClassCollection : ConfigurationElementCollection {
protected override ConfigurationElement CreateNewElement() {
return new SymbolClass();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((SymbolClass)element).Name;
}
}
[ConfigurationCollection(typeof(Symbol), AddItemName = "Symbol")]
public class SymbolClass : ConfigurationElementCollection {
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public String Name {
get {
return this["name"] as String;
}
}
protected override ConfigurationElement CreateNewElement() {
return new Symbol();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((Symbol)element).Name;
}
}
[ConfigurationCollection(typeof(TemplateValue), AddItemName = "add")]
public class Symbol : ConfigurationElementCollection {
[ConfigurationProperty("name", IsRequired = true, IsKey = true)]
public String Name {
get {
return this["name"] as String;
}
}
[ConfigurationProperty("template", IsRequired = false)]
public String Template {
get {
return this["template"] as String;
}
}
[ConfigurationProperty("dataname", IsRequired = false)]
public String DataName {
get {
return this["dataname"] as String;
}
}
protected override ConfigurationElement CreateNewElement() {
return new TemplateValue();
}
protected override object GetElementKey(ConfigurationElement element) {
return ((TemplateValue)element).Index;
}
}
public class TemplateValue : ConfigurationElement {
[ConfigurationProperty("index", IsRequired = false, IsKey = true)]
public Int32 Index {
get {
return this["index"] == null ? -1 : Convert.ToInt32(this["index"]);
}
}
[ConfigurationProperty("value", IsRequired = false)]
public String Value {
get {
return this["value"] as String;
}
}
}
When I parse the section with this statement:
symbols = ConfigurationManager.GetSection("EmailSymbols") as EmailSymbols;
I receive this error message: "Unrecognized element 'Symbol'."
This is simply an area of .NET that I don't know my way around. Any help that anyone could give would be most appreciated.
Does my XML definition make sense and is it in the correct form? I want a collection of SymbolClass, each containing a collection of Symbol, each containing a collection of TemplateValue.
Again, thanks for your help.
Best Regards,
Jimmy
You could try to override the Init() method of the SymbolClass class:
protected override void Init()
{
base.Init();
this.AddElementName = "Symbol";
}
You an also remove [ConfigurationCollection(typeof(SymbolClass), AddItemName = "SymbolClass")] and the others like it from above the class declarations as their not doing anything.