Ok, let's see...
I have this ViewModel Class, it has a builder to retrieve data from storage, another method who asks data to Internet, it has a saver the notifypropertychange methods and the locator methods.
But the problem is how can I Bind it to a jumplistbox, since as I'm using Locator Binding I can't process it as a group to take the headers and order it.
public class FriendLocator
{
private Lazy<ViewModelFriends> mainVMFriends;
public FriendLocator()
{
mainVMFriends = new Lazy<ViewModelFriends>(() => new ViewModelFriends());
}
public ViewModelFriends MainVMFriends
{
get
{
return mainVMFriends.Value;
}
}
}
public class VMFriendsBase : INotifyPropertyChanged
{
public VMFriendsBase()
{ }
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class ViewModelFriends : VMFriendsBase
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
private ObservableCollection<User_friend> Friends;
public ObservableCollection<User_friend> friends
{
get
{
return Friends;
}
set
{
Friends = value;
RaisePropertyChanged("friends");
}
}
public ViewModelFriends()
{
ObservableCollection<User_friend> a = new ObservableCollection<User_friend>();
if (settings.Contains("userFriends"))
{
string listado = settings["userFriends"] as string;
var listajson = JsonConvert.DeserializeObject<objetoslistas.getmyfriends>(listado);
if (listajson.profile != null)
{
foreach (objetoslistas.User user in listajson.profile)
{
User_friend usuario = new User_friend(user);
a.Add(usuario);
}
}
}
friends = a;
AskFriends();
}
public async void AskFriends()
{
ObservableCollection<User_friend> a = new ObservableCollection<User_friend>();
Uri url = new Uri(link);
objetoslistas.GetByUserID paquete = new objetoslistas.GetByUserID();
string respuesta = await metodosJson.jsonPOST(url, paquete);
var respuestajson = JsonConvert.DeserializeObject<objetoslistas.getmyfriends>(respuesta.ToString());
if (respuestajson.error == "")
{
saveFriends(respuesta);
if (respuestajson.profile != null)
{
foreach (objetoslistas.User user in respuestajson.profile)
{
User_friend usuario = new User_friend(user);
a.Add(usuario);
}
}
}
friends = a;
}
public void saveFriends(string jsonfriends)
{
if (!settings.Contains("userFriends"))
settings.Add("userFriends", jsonfriends);
else
settings["userFriends"] = jsonfriends;
settings.Save();
}
}
The methods I use to process data to listbox are
public static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, string> getKeyFunc)
{
IEnumerable<Group<T>> groupList = from item in itemList
group item by getKeyFunc(item) into g
orderby g.Key
select new Group<T>(g.Key, g);
return groupList.ToList();
}
public class Group<T> : List<T>
{
public Group(string name, IEnumerable<T> items)
: base(items)
{
this.Title = name;
}
public string Title
{
get;
set;
}
}
Thanks to all
Ok, I finaly solved by myself, I made a conversor like this:
public class ObservableToGroupedConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var group = (value as ViewModelFriends).friends;
return metodosAuxiliares.GetItemGroups(group.OrderBy(o => o.distraw).ToList(), c => c.online);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I added the conversor to the resources and the binding is:
<view:ViewFriends x:Name="vistaAmigos"
DataContext="{Binding MainVMFriends,
Source={StaticResource friendLocator},
Converter={StaticResource friendConvert}}"/>
Related
I created a MTObservableCollection class that derives from ObservableCollection for multithreading. This is how the function looks like:
public class MTObservableCollection<T> : ObservableCollection<T> where T: LogClassa
{
public MTObservableCollection() { }
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
if (CollectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
dispatcher.BeginInvoke(
(Action)(() => nh.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
And here is my LogClass
public class LogClass : INotifyPropertyChanged
{
private string timestamp;
private string title;
private string message;
private MTObservableCollection<LogClass> childRowLog = new MTObservableCollection<LogClass>();
public string TimeStamp
{
get { return timestamp; }
set
{
if( timestamp != value )
{
timestamp = value;
OnPropertyChanged("TimeStamp");
}
}
}
public string Title
{
get { return title; }
set
{
if( title!= value )
{
title= value;
OnPropertyChanged("Title");
}
}
}
public string Message
{
get { return message; }
set
{
if( message!= value )
{
message= value;
OnPropertyChanged("Message");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
So if I have two MTObservableCollection collections and I add elements to one of them such as:
public static MTObservableCollection<LogClass> parentLogCollection = new MTObservableCollection<LogClass>();
public MTObservableCollection<LogClass> childLogCollection = new MTObservableCollection<LogClass>();
childLogClass.Add( new LogClass { TimeStamp = "time", Title = "title", Message = "message" } );
Now if I want to add childLogCollection to parentLogCollection, I would do this:
parentLogCollection = new MTObservableCollection<LogClass>(childLogCollection);
I would think I need to create an implementation within the MBObservationCollection class which should be
public MTObservableCollection(MTObservableCollection<T> collection)
{
}
I just don't know what to input into it, how would I perform it?
Try changing the parent of your MTObservableCollection like this:
public MTObservableCollection(MTObservableCollection<T> collection) : base(collection)
{
}
I have a WPF project with a Ribbon ComboBox showing a list of countries that I'm trying to filter depending upon a selected RadioButton option (All, Africa, Asia, Europe). I'm basing my code on COMBOBOX filtering in WPF with MVVM which uses a ComboBox to select a continent and show the filtered countries in a ListBox but I'm having trouble converting this to use RadioButtons.
There's a problem with the XAML isChecked="..." lines which appear to cause an 'Input string was not in a correct format' error in the EnumBooleanConverter but if I change them to 'ConverterParameter=0' the app runs. I based this on How to bind RadioButtons to an enum?.
The default list of countries is initially shown in the ComboBox but the default country isn't displayed, instead it's blank.
Clicking on a RadioButton has no effect on the list.
Clearly I'm doing something wrong but I don't know what. Can you help?
XAML:
<ribbon:RibbonRadioButton x:Name="AllContinents"
GroupName="Continents"
IsChecked="{Binding Path=SelectedRadioGroup, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:mySettings+Continent.All}}"> <= Causes run error
</ribbon:RibbonRadioButton>
<ribbon:RibbonRadioButton x:Name="Africa"
GroupName="Continents"
IsChecked="{Binding Path=SelectedRadioGroup, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:mySettings+Continent.Africa}}"> <= Causes run error
</ribbon:RibbonRadioButton>
C# Code behind (DataContext):
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
public class MySettings : INotifyPropertyChanged
{
private ObservableCollection<Country> countries;
private ContinentViewModel selectedContinent;
public ListCollectionView CountryView { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ContinentViewModel> Continents { get; set; }
private static string selectedCountry = "Germany"; // Default country
public MySettings()
{
countries =
new ObservableCollection<Country>(
new[]
{
new Country() { Continent = Continent.Africa, DisplayName = "Algeria" },
new Country() { Continent = Continent.Africa, DisplayName = "Egypt" },
new Country() { Continent = Continent.Europe, DisplayName = "France" }
new Country() { Continent = Continent.Europe, DisplayName = "Germany" }
});
CountryView = new ListCollectionView(countries);
CountryView.Filter = o => selectedContinent == null || ((Country)o).Continent == selectedContinent.Model;
Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c}));
}
public ListCollectionView CountryView
{
get { return countryView; }
set
{
countryView = value;
}
}
public class Country
{
public string DisplayName { get; set; }
public Continent Continent { get; set; }
}
public enum Continent
{
All,
Africa,
Asia,
Europe,
America
}
public class ContinentViewModel
{
public Continent Model { get; set; }
public string DisplayName
{
get
{
return Enum.GetName(typeof(Continent), Model);
}
}
}
public ContinentViewModel SelectedContinent
{
get { return selectedContinent; }
set
{
selectedContinent = value;
OnContinentChanged();
this.OnPropertyChanged("SelectedContinent");
}
}
private void OnContinentChanged()
{
CountryView.Refresh();
}
public int SelectedRadioGroup
{
get { return selectedRadioGroup; }
set
{
selectedRadioGroup = value;
}
}
public string SelectedCountry
{
get { return selectedCountry; }
set
{
if (selectedCountry == value) return;
selectedCountry = value;
OnPropertyChanged(nameof(SelectedCountry));
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class EnumBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int integer = (int)value;
return integer == int.Parse(parameter.ToString()) ? true : (object)false; <= Error:Input string was not in a correct format
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? parameter : Binding.DoNothing;
}
}
I would have a bool property for each radio button rather than using an converter. Then do the check in your filter.
CountryView.Filter += CountryFilter;
private bool _All;
private bool _Africa;
private bool _Asia;
private bool _Europe;
private bool _America;
public bool All { get=>_All; set { _All=value; CountryView.Refresh(); } }
public bool Africa { get=> _Africa; set { _Africa=value; CountryView.Refresh(); } }
public bool Asia { get=> _Asia; set { _Asia=value; CountryView.Refresh(); } }
public bool Europe { get=> _Europe; set { _Europe=value; CountryView.Refresh(); } }
public bool America { get=> _America; set { _America=value; CountryView.Refresh() ;} }}
private bool CountryFilter(object obj)
{
var country = obj as Country;
if (country== null) return false;
if (All) return true;
if (Africa) return country.Continent == Continent.Africa;
if (Asia) return country.Continent == Continent.Asia;
if (Europe) return country.Continent == Continent.Europe;
if (America) return country.Continent == Continent.America;
return true;
}
I have a JSON class file which contains three classes, all of which follow this structure:
public class ManifestJSON : INotifyPropertyChanged
{
[JsonProperty("dataType")]
private string dataType;
public string DataType
{
get
{
return dataType;
}
set
{
if(dataType != value)
{
dataType = value;
RaisePropertyChanged("DataType");
}
}
}
[JsonProperty("ttl")]
private int time_to_live;
public int Time_To_Live
{
get
{
return time_to_live;
}
set
{
if (time_to_live != value)
{
time_to_live = value;
RaisePropertyChanged("Time_To_Live");
}
}
}
[JsonProperty("serial")]
private long serial;
public long Serial
{
get
{
return serial;
}
set
{
if (serial != value)
{
serial = value;
RaisePropertyChanged("Serial");
}
}
}
[JsonProperty("modifiedIso8601")]
private string modifiedIso8601;
public string ModifiedIso8601
{
get
{
return modifiedIso8601;
}
set
{
if (modifiedIso8601 != value)
{
modifiedIso8601 = value;
RaisePropertyChanged("ModifiedIso8601");
}
}
}
[JsonProperty("modifiedTimestamp")]
private long modifiedTimestamp;
public long ModifiedTimestamp
{
get
{
return modifiedTimestamp;
}
set
{
if (modifiedTimestamp != value)
{
modifiedTimestamp = value;
RaisePropertyChanged("ModifiedTimestamp");
}
}
}
[JsonProperty("timezone")]
private string timezone;
public string Timezone
{
get
{
return timezone;
}
set
{
if (timezone != value)
{
timezone = value;
RaisePropertyChanged("Timezone");
}
}
}
[JsonProperty("exports")]
private ObservableCollection<ManifestItem> manifest_Items;
public ObservableCollection<ManifestItem> Manifest_Items
{
get
{
return manifest_Items;
}
set
{
if (manifest_Items != value)
{
manifest_Items = value;
RaisePropertyChanged("Manifest_Items");
}
}
}
//Event handling
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
Console.WriteLine("Updated");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
In another class, I've created a global instance of type ManifestJSON
public ManifestJSON manifestData;
which is filled by deserializing a JSON string into this object using the DeserializeObject method from the Newtonsoft.json library like so:
manifestData = JsonConvert.DeserializeObject<ManifestJSON>(JSONString).
This fills the ManifestJSON class successfully, but none of my property methods or events are triggering. What am I doing wrong here?
If you want to update your existing data-bound ManifestJSON object, you should not replace this one with a new object but de-serialize the JSON string into new object and then set the properties of the existing manifestData object:
var newData = JsonConvert.DeserializeObject<ManifestJSON>(JSONString);
manifestData.DataType = newData.DataType;
manifestData.Time_To_Live = newData.Time_To_Live;
manifestData.Serial = newData.Serial;
//...
Instead of directly exposing entire Model to the View, I want to have ViewModel properties which are just proxies for each Model properties. For example;
private Product _product;
public string ProductName
{
get { return _product.ProductName; }
set
{
SetProperty(ref _product.ProductName, value);
}
}
But the above example causes the error of A property, indexer or dynamic member access may not be passed as an out or ref parameter.
How should I solve this problem?
P.S. My Models are not implemented by INPC interface. They are just simple POCO classes.
What you want is a façade or decorator object that will act as your model in your VM, not wrapping every model property with ViewModel properties. This allows you to not only reuse your models (facades/decorators), but it also keeps the concerns where they belong. You define your properties just like chipples provided, but call OnPropertyChanged() in the setter. You can't use the SetProperty method when wrapping other properties.
Something similar to this:
class Person
{
public string Name { get; set; }
}
class PersonFacade : BindableBase
{
Person _person;
public string Name
{
get { return _person.Name; }
set
{
_person.Name = value;
OnPropertyChanged();
}
}
}
class ViewModel : BindableBase
{
private PersonFacade _person;
public PersonFacade Person
{
get { return _person; }
set { SetProperty(ref _person, value); }
}
}
Maybe this is an old thread but C# MVVM property makes me stressed. Imagine You need to write 200 properties a day.
I have another approach to creating BaseClass.
public abstract class NotifyPropertiesBase : INotifyPropertyChanged, INotifyPropertyChanging
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
readonly Dictionary<string, object> _propertyStore = new Dictionary<string, object>();
public PropertyChangingEventArgs NotifyChanging([CallerMemberName] string propertyName = null)
{
var arg = new PropertyChangingEventArgs(propertyName);
PropertyChanging?.Invoke(this, arg);
return arg;
}
public PropertyChangedEventArgs NotifyChanged([CallerMemberName] string propertyName = null)
{
var arg = new PropertyChangedEventArgs(propertyName);
PropertyChanged?.Invoke(this, arg);
return arg;
}
public void SetPropValue(object newValue, [CallerMemberName] string propertyName = null)
{
if (GetType().GetMember(propertyName).Count() != 1)
throw new NotSupportedException($"\"{propertyName}\" Not Supported or maybe its not a Property");
var member = GetType().GetMember(propertyName).FirstOrDefault();
if (member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException($"Not Support Member Type {member.MemberType}");
var pInfo = member.DeclaringType.GetProperties().First();
NotifyChanging(propertyName);
if (!_propertyStore.ContainsKey(propertyName))
_propertyStore.Add(propertyName, newValue);
else
_propertyStore[propertyName] = newValue;
NotifyChanged(propertyName);
}
public T GetPropertyValue<T>([CallerMemberName] string propertyName = null)
{
return (T)GetPropertyValue(propertyName);
}
public object GetPropertyValue([CallerMemberName] string propertyName = null)
{
if (GetType().GetMember(propertyName).Count() != 1)
throw new NotSupportedException($"\"{propertyName}\" Not Supported or maybe its not a Property");
var member = GetType().GetMember(propertyName).FirstOrDefault();
if (member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException($"Not Support Member Type {member.MemberType}");
var pInfo = member.DeclaringType.GetProperties().First();
if (!_propertyStore.ContainsKey(propertyName))
{
_propertyStore.Add(propertyName, GetDefault(pInfo.PropertyType));
}
return _propertyStore[propertyName];
}
object GetDefault(Type t)
{
if (t.IsValueType)
{
return Activator.CreateInstance(t);
}
return null;
}
}
Class Usages:
class Program
{
static void Main(string[] args)
{
var t = new Test();
t.PropertyChanged += T_PropertyChanged;
t.ValueTest = "Hello World!";
var data = t.GetPropertyValue(nameof(t.ValueTest));
Console.Write(data);
}
private static void T_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine(e.PropertyName);
}
}
public class Test : NotifyPropertiesBase
{
public string ValueTest
{
get => GetPropertyValue<string>();
set => SetPropValue(value);
}
}
It is simple make with helper class like ViewModelBase, which simplifies raise PropertyChanged event:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(ExtractPropertyName(propertyExpression)));
}
private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException("propertyExpression");
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
throw new ArgumentException("memberExpression");
var property = memberExpression.Member as PropertyInfo;
if (property == null)
throw new ArgumentException("property");
var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic)
throw new ArgumentException("static method");
return memberExpression.Member.Name;
}
}
then, simple POCO class Person:
class Person
{
public string Name { get; set; }
public double Age { get; set; }
}
we can wrap to ViewModel like:
public class PersonViewModel : ViewModelBase
{
private readonly Person person = new Person();
public string Name
{
get { return person.Name; }
set
{
person.Name = value;
OnPropertyChanged(() => Name);
}
}
public double Age
{
get { return person.Age; }
set
{
person.Age = value;
OnPropertyChanged(() => Age);
}
}
}
SetProperty is not needed here, you can just do this:
private Product _product;
public string ProductName
{
get { return _product.ProductName; }
set
{
_product.ProductName = value;
}
}
I want people who use my custom control to choose a constant with a simple dropdown. The control should be reusable and therefor resides in a library so it can't access an enum, and the constants could in fact be defined anywhere.
Problem is that AppDomain.CurrentDomain.GetAssemblies() does not contain the current project you are designing in. And when I create a separate project it sometimes works but mostly it doesn't. And with doesn't work I mean: It can't find any classes/constants defined in the library, so they don't show up in the dropdown.
Everything else already works. The dropdown works. Code generation is a but clunky but it works. And I can always find constants defined in TestControl itself.
It seems like the designer itself doesn't always load all the assemblies/projects which are available. So how can I load the project which I need within the context of the designer/visual studio itself? Or how do I reference/find other projects within my list of dependencies from within the UITypeEditor?
I have created my own TestControl:
public partial class TestControl : UserControl, IHasTags
{
public static readonly ITestItem A = new TestItemImpl(null, "A", "Aap");
public static readonly ITestItem B = new TestItemImpl(null, "B", "B");
public static readonly ITestItem C_xx = new TestItemImpl(null, "C", "C");
public static readonly ITestItem D = new TestItemImpl(null, "D", "D");
[Editor(typeof(ItemEditor), typeof(UITypeEditor))]
public ITestItem item { get; set; }
public TestControl()
{
InitializeComponent();
}
}
With my own editor:
public class ItemEditor : UITypeEditor
{
private IWindowsFormsEditorService _editorService;
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// drop down mode (we'll host a listbox in the drop down)
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
_editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
// use a list box
ListBox lb = new ListBox();
lb.SelectionMode = SelectionMode.One;
lb.SelectedValueChanged += OnListBoxSelectedValueChanged;
lb.Width = 300;
// get the analytic object from context
// this is how we get the list of possible benchmarks
TestControl ctrl = (TestControl)context.Instance;
// Add all test items
IList<StaticFieldInfo<ITestItem>> items = ClassHelper.getStaticFields<IHasTags, ITestItem>();
foreach (StaticFieldInfo<ITestItem> item in items)
{
lb.Items.Add(item);
}
// show this model stuff
_editorService.DropDownControl(lb);
if (lb.SelectedItem == null) // no selection, return the passed-in value as is
return value;
StaticFieldInfo<ITestItem> result = (StaticFieldInfo<ITestItem>)lb.SelectedItem;
return result.value;
}
private void OnListBoxSelectedValueChanged(object sender, EventArgs e)
{
// close the drop down as soon as something is clicked
_editorService.CloseDropDown();
}
}
And I collect all constants with the following helper:
public class StaticFieldInfo<T>
{
public StaticFieldInfo(FieldInfo fieldInfo, T value)
{
this.fieldInfo = fieldInfo;
this.value = value;
}
public T value { get; private set; }
public FieldInfo fieldInfo { get; private set; }
public override string ToString()
{
return value.ToString() + " (" + fieldInfo.DeclaringType.FullName + "." + fieldInfo.Name + ")";
}
}
public class ClassHelper
{
public static IList<StaticFieldInfo<T>> getStaticFields<C, T>()
{
Type classType = typeof(C);
Type fieldType = typeof(T);
List<StaticFieldInfo<T>> result = new List<StaticFieldInfo<T>>();
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
foreach (Type t in asm.GetTypes())
{
if (classType.IsAssignableFrom(t))
{
foreach (FieldInfo f in t.GetFields())
{
if (f.IsStatic && fieldType.IsAssignableFrom(f.FieldType))
{
T value = (T)f.GetValue(null);
if (value != null)
{
result.Add(new StaticFieldInfo<T>(f, value));
}
}
}
}
}
}
catch (ReflectionTypeLoadException)
{
// Ignore errors
}
}
return result;
}
}
The rest of the code (less important):
public interface IHasTags
{
}
[TypeConverter(typeof(ITestItemConverter))]
public interface ITestItem
{
string driver { get; set; }
string tag { get; set; }
string name { get; set; }
}
public class ITestItemConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
// we only know how to convert from to a string
return typeof(string) == destinationType;
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value != null)
{
return value.ToString();
}
return "(none)";
}
}
[DesignerSerializer(typeof(ItemSerializer), typeof(CodeDomSerializer))]
public class TestItemImpl : ITestItem
{
public TestItemImpl()
{
}
public TestItemImpl(string driver, string tag, string name)
{
this.driver = driver;
this.tag = tag;
this.name = name;
}
public override string ToString()
{
return name;
}
public string driver { get; set; }
public string tag { get; set; }
public string name { get; set; }
}
public class ItemSerializer : CodeDomSerializer
{
public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
{
// This is how we associate the component with the serializer.
CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
GetSerializer(typeof(TestItemImpl).BaseType, typeof(CodeDomSerializer));
/* This is the simplest case, in which the class just calls the base class
to do the work. */
return baseClassSerializer.Deserialize(manager, codeObject);
}
public override object Serialize(IDesignerSerializationManager manager, object value)
{
/* Associate the component with the serializer in the same manner as with
Deserialize */
CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
GetSerializer(typeof(TestItemImpl).BaseType, typeof(CodeDomSerializer));
object codeObject = baseClassSerializer.Serialize(manager, value);
/* Anything could be in the codeObject. This sample operates on a
CodeStatementCollection. */
if (codeObject is CodeStatementCollection)
{
CodeStatementCollection statements = (CodeStatementCollection)codeObject;
StaticFieldInfo<ITestItem> field = null;
foreach (StaticFieldInfo<ITestItem> item in ClassHelper.getStaticFields<IHasTags, ITestItem>())
{
if (value == item.value)
{
field = item;
break;
}
}
// If field can be found (should be always)
if (field != null)
{
statements = new CodeStatementCollection();
statements.Add(new CodeSnippetExpression(typeof(ITestItem).FullName + " " + this.GetUniqueName(manager, value) + " = " + typeof(TestControl).FullName + "." + field.fieldInfo.Name));
codeObject = statements;
}
}
return codeObject;
}
}