Are There any better way than using ObservableCollection for fast Binding in XAML? - xaml

We are developing a Windows Phone application (CurrencyExchange) and there is a page that includes a textbox and a listbox. ListBox's itemsource is it's viewmodel's property type of observable collection. Textbox's textchange event is changing observable collection's all items but when observable changing and trying to bind listbox's items, the page is locking. I have seen a customobservable collection named Fastobservablecollection that is not running in viewmodel because it is using DispatcherObject and Dispatcherprioty that can't use in viewmodel. Are there any alternative that better than ObservableCollection?
List<Currency> newList = new List<Currency>(CurrencyConversions.ToList());
foreach (var item in newList)
{
Double result;
if (Double.TryParse(AmountPhone, NumberStyles.Any, new System.Globalization.CultureInfo("tr-TR"), out result))
item.CalculatedValue = Math.Round(result * (Direction == "0" ? item.ConversionRateSell : item.ConversionRateBuy), 2);
else
item.CalculatedValue = 0;
}
CurrencyConversions = new ObservableCollection<Currency>(newList);
or
List<Currency> newList = new List<Currency>();
foreach (var item in CurrencyConversions)
{
Double result;
if (Double.TryParse(AmountPhone, NumberStyles.Any, new System.Globalization.CultureInfo("tr-TR"), out result))
item.CalculatedValue = Math.Round(result * (Direction == "0" ? item.ConversionRateSell : item.ConversionRateBuy), 2);
else
item.CalculatedValue = 0;
newList.Add(item);
}
CurrencyConversions = new ObservableCollection<Currency>(newList);
Thanks.
With SmartCollection
List<Currency> newList = new List<Currency>(CurrencyConversions.ToList());
foreach (var item in newList)
{
Double result;
if (Double.TryParse(Amount, NumberStyles.Any, new System.Globalization.CultureInfo("tr-TR"), out result))
item.CalculatedValue =Math.Round( result * (Direction == "0" ? item.ConversionRateSell : item.ConversionRateBuy),2);
else
item.CalculatedValue = 0;
}
CurrencyConversions = new SmartCollection<Currency>(newList);

You should not create a new SmartCollection each time, but more use only one instance and make modifications to the collection. I would suggest to change the implementation of your property CurrencyConversions to the following.
private SmartCollection<Currency> _conversions;
public SmartCollection<Currency> CurrencyConversions{
get{
if (_conversions == null) {
_conversions = new SmartCollection<Currency>();
}
return _conversions;
}
}
Then you can call it like so in your code:
CurrencyConversions.Reset(newList);
As I currently understand your code, you are not changing (adding and removing items) the collection, but rather change the property CalculatedValue of the type Currency. When the type Currency implements the interface INotifyPropertyChanged there is no need to change the collection to update the UI, so changing your code to
foreach (var item in CurrencyConversions) {
Double result;
if (Double.TryParse(Amount, NumberStyles.Any, new System.Globalization.CultureInfo("tr-TR"), out result))
item.CalculatedValue =Math.Round( result * (Direction == "0" ? item.ConversionRateSell : item.ConversionRateBuy),2);
else
item.CalculatedValue = 0;
}
would be enough when your type implements INotifyPropertyChanged. For that to work the property CalculatedValue should look like:
private double _value;
public double CalculatedValue{
get{
return _value;
}
set{
_value = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("CalculatedValue"));
}
}
}

Related

Make [FromQuery] bool testValue accept 'testValue', 'test_value' and 'test-value'

In ASP NET 6+ I need to make [FromQuery] replace underscores _ and minuses - before matching names.
So I want to plumb ASP to allow [FromQuery] bool testValue to be equivalent to all at once:
[FromQuery(Name="testValue")] bool testValue
[FromQuery(Name="test-value")] bool testValue
[FromQuery(Name="test_value")] bool testValue
Is there a place in the pipeline I can get in before names are compared (to remove _ and - myself)?
My current solution is just to replace the Request.Query with my own doctored QueryCollection that duplicates variables with fixed names in a middleware.
But I'm looking for any answer that's more... unhacky?!
public class RequeryMiddleware : IMiddleware
{
private static readonly char[] separators = new[] { '_', '-', '.', '|' };
private static bool Requery(ref string name)
{
bool changed = false;
if (name.IndexOfAny(separators) >= 0)
{
name = string.Concat(name.Split(separators, StringSplitOptions.None));
changed = true;
}
return changed;
}
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
Dictionary<string, StringValues> mods = new(
StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
string key = item.Key;
if (Requery(ref key))
{
mods.Add(key, item.Value);
}
}
if (mods.Count > 0)
{
Dictionary<string, StringValues> query = new(
context.Request.Query.Count + mods.Count
, StringComparer.OrdinalIgnoreCase
);
foreach (var item in context.Request.Query)
{
query.Add(item.Key, item.Value);
}
foreach (var mod in mods)
{
// if we get here it's bad...
query.TryAdd(mod.Key, mod.Value);
}
// replace the Query collection
context.Request.Query = new QueryCollection(query);
// change the QueryString too
QueryBuilder qb = new(context.Request.Query);
context.Request.QueryString = qb.ToQueryString();
}
return next(context);
}
}

Mvel dynamic expression

Do you know if it's possible to dynamically evaluate an expression with Mvel. For example :
VariableResolverFactory functionFactory = new MapVariableResolverFactory();
MVEL.eval("def SUM(op1,op2,op3) { result=0B; if(op1) result+=op2; else result+=op3; } return result; ",functionFactory);
ParserContext ctx = new ParserContext()
Serializable s = MVEL.compileExpression("SUM(op1,op2,op3)", ctx);
contextMapFct.put("op1", "5 > 3"); // just as an example if it's useless
contextMapFct.put("op2", new BigDecimal(10));
contextMapFct.put("op3", new BigDecimal(30));
Object obj= MVEL.executeExpression(s, contextMapFct, this.functionFactory);
Few changes done
1.) Brace added at the last, was closing before return result;.
2.) int result=0, declaration added.
3.) if(op1 == 'true'), it is not coming as boolean, but as String
VariableResolverFactory functionFactory = new MapVariableResolverFactory();
MVEL.eval(
"def SUM(op1,op2,op3) { int result=0; if(op1 == 'true') result+=op2; else result+=op3; return result; }",
functionFactory);
ParserContext ctx = new ParserContext();
Serializable s = MVEL.compileExpression("SUM(op1,op2,op3)", ctx);
Map contextMapFct = new HashMap();
contextMapFct.put("op1", "5 > 3"); // just as an example if it's useless
contextMapFct.put("op2", new BigDecimal(10));
contextMapFct.put("op3", new BigDecimal(30));
Object obj = MVEL.executeExpression(s, contextMapFct, functionFactory);
System.out.println(obj);
output
30

How to use GroupFormatter with ObjectListView control

I cannot seem to find anywhere, any examples on how to make use of the GroupFormatter delegate to allow me to add footers to my groups when using the ObjectListView control.
Does anyone have any examples that could demonstrate this? I want to remove the text from the group header and add a footer (different text per footer). As well as changing font, etc.
Any examples would be very helpful.
You can analyze the code for the
public void MakeGroupies<T>(T[] values, string[] descriptions, object[] images, string[] subtitles, string[] tasks)
method of the ObjectListView class. That explicitly sets the GroupKeyGetter, GroupKeyToTitleConverter and GroupFormatter property delegates.
This is C# but your VB adaptation should be straightforward. I am using this small test class as the object type to bind to the list view.
public class TestClass
{
private readonly string _s;
private readonly float _f;
public TestClass( string p1, float p2 )
{
this._s = p1;
this._f = p2;
}
[OLVColumn(DisplayIndex = 1, Name="S", Title="String")]
public string S {get {return this._s;}}
[OLVColumn( DisplayIndex = 2, Name = "F", Title = "Float" )]
public float F {get {return this._f;}}
}
So as not to manually define column traits I am using attributes inside the bound object and a
BrightIdeasSoftware.Generator.GenerateColumns( this.olv, typeof( TestClass ) );
call in the form/user control where I am using the list view. In fact here is the method that completely isolates ObjectListView configuration:
void SetData( TestClass[] objects )
{
// build list columns
Generator.GenerateColumns( this.olv, typeof( TestClass ) );
// use groups and make current column the priimary sort column
this.olv.ShowGroups = true;
this.olv.SortGroupItemsByPrimaryColumn = false;
// loop through columns and set properties
foreach( OLVColumn col in this.olv.Columns )
{
col.Groupable = true;
col.Sortable = true;
if( col.Name == "F" )
{
col.MakeGroupies<float>( new float[] { 10f, 100f, 1000f }, new string[] { "<10", "10-100", "100-1000", ">1000" } );
}
else if( col.Name == "S" )
{
col.UseInitialLetterForGroup = false;
//
col.GroupKeyGetter = ( obj ) =>
{
TestClass tc = (TestClass)obj;
switch( char.ToLower( tc.S[0] ) )
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': return true;
default: return false;
}
};
//
col.GroupKeyToTitleConverter = ( o ) => { bool b = (bool)o; return b ? "vowel" : "consonant"; };
//
col.GroupFormatter = ( /*OLVGroup*/ group, /*GroupingParameters*/ parms ) =>
{
string s = string.Format ("{0} {1}", group.GroupId, group.Id);
//group.BottomDescription = "BottomDescription: " + s;
//group.TopDescription = "TopDescription: " + s;
group.Footer = "Footer: " + s;
};
}
}
//
this.olv.RebuildColumns();
//
this.olv.SetObjects( objects );
}
You will definitely have one different footer per each group.

Enum dropdownlistfor issue

I've read a possible solution to this, but would require a lot of rewriting, the possible solution is linked here, but there wouldn't be any sense to doing it that way if I am just a couple words off in my dropdownlistfor.
I'm having an issue with my dropdownlistfor as this is all new to me:
#Html.DropDownListFor(model => model.pageID, new SelectList (Enum.GetNames(typeof(PageIndex)), EnumHelper.GetSelectedItemList<PageIndex>().SelectedValue))
Trying to grab the "description" of my enum values as the drop down lists text values, then have an integer value returned to the database on POST.
Here's my enum:
public enum PageIndex : int
{
[Description("Developmental Disabilities Tip Sheet")]
ddTipSheets = 1,
[Description("Hiiiiiiiiiiiiiiiiiiii")]
Example1 = 2,
[Description("I don't know what I'm doing")]
Example2 = 3
};
and my EnumHelper:
public class EnumHelper
{
public static SelectList GetSelectedItemList<T>() where T : struct
{
T t = default(T);
if (!t.GetType().IsEnum) { throw new ArgumentNullException("Please make sure that T is of Enum Type"); }
var nameList = t.GetType().GetEnumNames();
int counter = 0;
Dictionary<int, String> myDictionary = new Dictionary<int, string>();
if (nameList != null && nameList.Length > 0)
{
foreach (var name in nameList)
{
T newEnum = (T) Enum.Parse(t.GetType(), name);
string description = getDescriptionFromEnumValue(newEnum as Enum);
if (!myDictionary.ContainsKey(counter))
{
myDictionary.Add(counter, description);
}
counter++;
}
counter = 0;
return new SelectList(myDictionary, "Key", "Value");
}
return null;
}
private static string getDescriptionFromEnumValue(Enum value)
{
DescriptionAttribute descriptionAttribute =
value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.SingleOrDefault() as DescriptionAttribute;
return descriptionAttribute == null ?
value.ToString() : descriptionAttribute.Description;
}
}

C# Linked List, Tracks Head + Tail with APIs InsertAfter + Remove. See any flaws or optimizations?

Another data structure I wrote under interview conditions. It is essentially a generic linked list that tracks the head and tail of the list (probably just for academic exercise, in RL life you'd just use List). Does anyone see any possible flaws or optimizations?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SingleLinkedHeadAndTail
{
class SingleListEntry<T>
{
public T Data { get; set; }
public SingleListEntry<T> Next {get; set;}
public SingleListEntry(T data)
{
Data = data;
}
}
public class SingleListExample<T>
{
private SingleListEntry<T> head;
private SingleListEntry<T> tail;
public int length { get; set; }
public T Head
{
get
{
if (head != null)
{
return head.Data;
}
return default(T);
}
}
public T Tail
{
get
{
if (tail != null)
{
return tail.Data;
}
return default(T);
}
}
public void Insert(T data)
{
if (head==null)
{
head = new SingleListEntry<T>(data);
tail = head;
length++;
}
else
{
tail.Next = new SingleListEntry<T>(data);
tail = tail.Next;
length++;
}
}
public void InsertAfter(T data, int position)
{
if (position < 0)
{
throw new Exception("no soup for you - position must be 0 or higher");
}
if (head == null)
{
throw new Exception("sorry, you cannot insert after nothing, the list is empty.");
}
if (position >= length) //we could allow this stuff and padd out the list etc, but for now...no soup.
{
throw new Exception("Position requested is > then the length of the list.");
}
if (position == length - 1) //just an inswer
{
Insert(data);
return;
}
SingleListEntry<T> newElement = new SingleListEntry<T>(data);
SingleListEntry<T> temp = GetElementAt(position);
newElement.Next = temp.Next;
temp.Next = newElement;
length++;
}
public T GetElement(int position)
{
return GetElementAt(position).Data;
}
private SingleListEntry<T> GetElementAt(int position)
{
SingleListEntry<T> temp = head;
//pop down N levels until position
int counter = 0;
while (counter < position)
{
temp = temp.Next;
counter++;
if (temp == null && counter < position) //should have been caught
{
throw new Exception(String.Format("{0} elements do not exist", position));
}
}
return temp;
}
public void Remove(int position)
{
if (position < 0)
{
throw new Exception("no soup for you - position must be 0 or higher");
}
if (head == null)
{
throw new Exception("sorry, you cannot remove from nothing, the list is empty.");
}
if (position >= length) //we could allow this stuff and padd out the list etc, but for now...no soup.
{
throw new Exception("Position requested is > then the length of the list.");
}
if (position == 0) //head
{
head = head.Next;
length--;
return;
}
SingleListEntry<T> temp;
temp = GetElementAt(position - 1);
if (position == length-1)
{
tail = temp;
tail.Next = null;
length--;
return;
}
temp.Next = temp.Next.Next;
length--;
}
}
class Program
{
static void Main(string[] args)
{
Test1();
Test2();
Test3();
}
public static void Test1()
{
SingleListExample<string> myList = new SingleListExample<string>();
myList.Insert("joe");
myList.Insert("mike");
myList.Insert("adam");
if (myList.Head != "joe") throw new Exception("fail");
if (myList.Tail != "adam") throw new Exception("fail");
if (myList.GetElement(1) != "mike") throw new Exception("fail");
}
public static void Test2()
{
SingleListExample<string> myList = new SingleListExample<string>();
myList.Insert("joe");
myList.Insert("mike");
myList.Insert("adam");
myList.InsertAfter("paul", 1);
myList.InsertAfter("john", 0);
myList.InsertAfter("nichole", 4);
if (myList.Tail != "nichole") throw new Exception("fail");
if (myList.Head!= "joe") throw new Exception("fail");
if (myList.GetElement(0) != "joe") throw new Exception("fail");
if (myList.GetElement(1) != "john") throw new Exception("fail");
if (myList.GetElement(2) != "mike") throw new Exception("fail");
if (myList.GetElement(3) != "paul") throw new Exception("fail");
if (myList.GetElement(4) != "adam") throw new Exception("fail");
if (myList.GetElement(5) != "nichole") throw new Exception("fail");
}
public static void Test3()
{
SingleListExample<string> myList = new SingleListExample<string>();
myList.Insert("joe");
myList.Insert("mike");
myList.Insert("adam");
myList.InsertAfter("paul", 1);
myList.InsertAfter("john", 0);
myList.InsertAfter("nichole", 4);
myList.Remove(0);
if (myList.Head != "john") throw new Exception("fail");
myList.Remove(myList.length-1);
if (myList.Tail != "adam") throw new Exception("fail");
myList.Remove(1);
if (myList.Head != "john") throw new Exception("fail");
if (myList.Tail != "adam") throw new Exception("fail");
if (myList.GetElement(0) != "john") throw new Exception("fail");
if (myList.GetElement(1) != "paul") throw new Exception("fail");
if (myList.GetElement(2) != "adam") throw new Exception("fail");
}
}
}
Implement an iterator. Your GetElementAt method is begging people to walk the list using Schlemiel the Painter's Algorithm.
To clarify: For each element in the list, GetElementAt has to start from the beginning and count out entries to the index of the entry you want. So getting the entries from 1 to...say..a million would (internally) involve running through the list a million times. Walking the list becomes an O(N^2) operation, which defeats one of the purposes of a list -- fast sequential access. Contrast that with an iterator, which would keep track of its place in the list and just get the next entry each time, avoiding the 0..n loop and making traversal a whole lot faster.
It looks fundamentally sound code (ignoring the design considerations of using Collection interafces like enumeration, indexers, etc)
All the validity checks could be put into a 'CheckValid' method that is simply called from your other methods. The compiler should have no problem inlining it, so you shouldn't see a performance degradation as a result (and of course, if performance is key, you'd use asserts, not runtime checks)
GetElementAt checks if it should throw the exception on every iteration. It could just check that the position value is within the list length before starting to enumerate items. (It will also crash if the list is empty and a nonzero position is passed in). It should really validate that position >= 0 too.
The code for Remove and InsertAfter could use a common method which returns the items at position and position-1. THis would reduce the code needed and halve the amount of testing required, although it would add a tiny 'avoidable overhead' to InsertAfter.
I'd tend to name Insert "Add" or "Append" myself, because it's not inserting.
You might consider returning the data from the item you Remove - otherwise you have to search the whole list twice to read a value and then remove it.