Modifying List in ViewState does not persist - c#

I have a ViewState holding a List<T>
public List<AwesomeInt> MyList
{
get { return ((List<int>)ViewState["MyIntList"]).Select(i => new AwesomeInt(i)).ToList(); }
set { ViewState["MyIntList"] = value.GetIntegers(); }
}
Now, when I call MyList.Add(new AwesomeInt(3)) let's say, the list does not persist the change.
I believe this is because the .ToList() in the get is creating a new List object and therefore the set will never be called, thus never saving in ViewState.
I have worked around this problem before by either
not calling .Select/.ToList() by saving/calling directly without a
conversion.
not using the .Add or .Remove functions and instead
re-initializing the List with an equals.
However sometimes 1. is impractical if the class is not serializable and I have no control over that, and 2. is kind of ugly because I have to copy it to a temp first, then add, then re-assign, or play around with Concat to add a single item.
Is there a better way of doing this?

Alright, below is a fully functional console application that should give you the capabilities you need. I leveraged generics so that you could build surrounding collections of whatever type necessary - but yet serialize something more rudimentary. Keep in mind I don't have a real view state to write to in the set but you can fix that up.
Also bear in mind I wrote this in a pretty short time frame (e.g. 20 minutes) so there may be optimizations that exist (e.g. the set on the ViewState property isn't really necessary generally because this solution modifies the underlying rudimentary data source).
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static List<int> _viewState = new List<int>();
static RawCollection<AwesomeInt, int> ViewState
{
get { return new RawCollection<AwesomeInt, int>(_viewState); }
set { _viewState = value.RawData; }
}
static void Main(string[] args)
{
ViewState.Add(new AwesomeInt(1));
ViewState.Add(new AwesomeInt(2));
WriteViewState();
ViewState[0].Val = 5;
WriteViewState();
ViewState.RemoveAt(0);
WriteViewState();
for (int i = 10; i < 15; i++)
{
ViewState.Add(new AwesomeInt(i));
}
WriteViewState();
}
private static void WriteViewState()
{
for (int i = 0; i < ViewState.Count; i++)
{
Console.WriteLine("The value at index {0} is {1}.", i, ViewState[i].Val);
}
Console.WriteLine();
Console.WriteLine();
}
}
public class RawCollection<T, K> : Collection<T>
{
private List<K> _data;
public RawCollection(List<K> data)
{
foreach (var i in data)
{
var o = (T)Activator.CreateInstance(typeof(T), i);
var oI = o as IRawData<K>;
oI.RawValueChanged += (sender) =>
{
_data[this.IndexOf((T)sender)] = sender.Val;
};
this.Add(o);
}
_data = data;
}
public List<K> RawData
{
get
{
return new List<K>(
this.Items.Select(
i => ((IRawData<K>)i).Val));
}
}
protected override void ClearItems()
{
base.ClearItems();
if (_data == null) { return; }
_data.Clear();
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
if (_data == null) { return; }
_data.Insert(index, ((IRawData<K>)item).Val);
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
if (_data == null) { return; }
_data.RemoveAt(index);
}
protected override void SetItem(int index, T item)
{
base.SetItem(index, item);
if (_data == null) { return; }
_data[index] = ((IRawData<K>)item).Val;
}
}
public class AwesomeInt : IRawData<int>
{
public AwesomeInt(int i)
{
_val = i;
}
private int _val;
public int Val
{
get { return _val; }
set
{
_val = value;
OnRawValueChanged();
}
}
public event Action<IRawData<int>> RawValueChanged;
protected virtual void OnRawValueChanged()
{
if (RawValueChanged != null)
{
RawValueChanged(this);
}
}
}
public interface IRawData<T> : INotifyRawValueChanged<T>
{
T Val { get; set; }
}
public interface INotifyRawValueChanged<T>
{
event Action<IRawData<T>> RawValueChanged;
}
}

Related

CS1503 Argument 1: cannot convert from 'Poc.Core.Player' to 'Poc.Interfaces.IScheduleable'

sorry im newish to programming so this may be an easy solvable problem that im not knowledgeable enough to know how to fix
Im using this tutorial for a simple dungeon crawler https://bitbucket.org/FaronBracy/roguesharpv3tutorial/src/master/
when it came to implementing the behaviors of the kobolds (mutants in my project) i would get an error saying 'Argument 1: cannot convert from 'Poc.Core.(Player/monster)" to "Poc.Interface.ISchedule"
this was happening on the addplayer void, addmonster void, and removemonster void in the DungeonMap.cs and twice on the ActivateMonsters void in CommandSystem.cs
i would appreciate it so much if someone could help me fix this problem
problem voids:
public void AddPlayer(Player player)
{
Game.Player = player;
SetIsWalkable(player.X, player.Y, false);
UpdatePlayerFieldOfView();
**Game.SchedulingSystem.Add(player);**
}
public void AddMonster(Monster monster)
{
_monsters.Add(monster);
// After adding the monster to the map make sure to make the
cell not walkable
SetIsWalkable(monster.X, monster.Y, false);
**Game.SchedulingSystem.Add( monster );**
}
public void RemoveMonster(Monster monster)
{
_monsters.Remove(monster);
SetIsWalkable(monster.X, monster.Y, true);
**SchedulingSystem.Remove(monster);**
}
public void ActivateMonsters()
{
IScheduleable scheduleable = Game.SchedulingSystem.Get();
if (scheduleable is Player)
{
IsPlayerTurn = true;
**Game.SchedulingSystem.Add(Game.Player);**
}
else
{
Monster monster = scheduleable as Monster;
if (monster != null)
{
monster.PerformAction(this);
**Game.SchedulingSystem.Add(monster);**
}
ActivateMonsters();
}
}
then my Scheduling System code
namespace Poc.Systems
{
public class SchedulingSystem
{
private int _time;
private readonly SortedDictionary<int, List<IScheduleable>> _scheduleables;
public SchedulingSystem()
{
_time = 0;
_scheduleables = new SortedDictionary<int, List<IScheduleable>>();
}
public void Add(IScheduleable scheduleable)
{
int key = _time + scheduleable.Time;
if (!_scheduleables.ContainsKey(key))
{
_scheduleables.Add(key, new List<IScheduleable>());
}
_scheduleables[key].Add(scheduleable);
}
public void Remove(IScheduleable scheduleable)
{
KeyValuePair<int, List<IScheduleable>> scheduleableListFound
= new KeyValuePair<int, List<IScheduleable>>(-1, null);
foreach (var scheduleablesList in _scheduleables)
{
if (scheduleablesList.Value.Contains(scheduleable))
{
scheduleableListFound = scheduleablesList;
break;
}
}
if (scheduleableListFound.Value != null)
{
scheduleableListFound.Value.Remove(scheduleable);
if (scheduleableListFound.Value.Count <= 0)
{
_scheduleables.Remove(scheduleableListFound.Key);
}
}
}
public IScheduleable Get()
{
var firstScheduleableGroup = _scheduleables.First();
var firstScheduleable = firstScheduleableGroup.Value.First();
Remove(firstScheduleable);
_time = firstScheduleableGroup.Key;
return firstScheduleable;
}
// Get the current time (turn) for the schedule
public int GetTime()
{
return _time;
}
{
_time = 0;
_scheduleables.Clear();
}
}
}
Make sure that your Actor class, which Player and Monster inherit from, is implementing IScheduleable:
public class Actor : IActor, IDrawable, IScheduleable
{
// ... Previous Actor code omitted
// IScheduleable
public int Time
{
get
{
return Speed;
}
}
}

Fire property on list add

Just as title says, how to fire property when I do propertyList.Add(something)
So code is:
private List<string> _SomeStrings;
public List<string> SomeStrings
{
get
{
return _SomeStrings;
}
set
{
_SomeStrings = value;
}
odAdd //this is what I need but do not know how to do it
}
You can either use a built in type such as ObservableCollection; examples here and here. MSDN page.
You could also create a new class that derives from List, and overloads the functions you wish to hook.
class ListWithAdd<T> : List<T>
{
public new void Add(T item)
{
base.Add(item);
DoStuff();
}
}
Create a custom generic list, create a event which will be fired when an item is added in the list.
like this:
namespace ConsoleApplication2
{
public delegate void OnAddEventHandler(object item);
public class AddEventArgs : EventArgs
{
public object item { get; set; }
}
public class MyList<T> : List<T>
{
public event OnAddEventHandler OnAdd;
public new void Add(T item)
{
base.Add(item);
if (OnAdd != null)
{
OnAdd(item);
}
}
}
class Program
{
static void Main(string[] args)
{
MyList<string> lst = new MyList<string>();
lst.OnAdd += (item) => {
Console.WriteLine("new item added: " + item);
};
lst.Add("test");
Console.ReadLine();
}
}
}
here's fiddle for you: https://dotnetfiddle.net/tc5Mq1
Look into observablecollection https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netframework-4.7.2

How to pass a List<Interface> and an implemented method from another class

I have a Game Manager, which is used to manage the execution order of specific Unity callbacks (FixedUpdate, Update and LateUpdate) in all the other scripts.
Specifically, I wrote these 3 interfaces:
public interface IFixedAt {
bool IsActive { get; }
void FixedAt();
}
public interface IUpdateAt {
bool IsActive { get; }
void UpdateAt();
}
public interface ILateUpdateAt {
bool IsActive { get; }
void LateUpdateAt();
}
These interfaces are implemented in game objects' scripts, where needed, like this for example:
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour, IUpdateAt, ILateUpdateAt {
[SerializeField]
bool isActive = true;
public bool IsActive {
get {
return (isActive && gameObject.activeInHierarchy);
}
}
public void UpdateAt() {
// Do stuff in Update
}
public void LateUpdateAt() {
// Do stuff in Late Update
}
}
The Game Manager script gets at Awake the reference to all scripts which implement the interfaces, creating a List<Interface> and then uses the list at runtime to execute the callbacks only where needed:
using UnityEngine;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public List<GameObject> GameObjectsWithScripts;
List<IFixedAt> fixedAtList { get; set; }
List<IUpdateAt> updateAtList { get; set; }
List<ILateUpdateAt> lateUpdateAtList { get; set; }
private void Awake() {
PopulateAllLists();
}
private void FixedUpdate() {
if (fixedAtList != null) {
for (int i = 0; i < fixedAtList.Count; i++) {
if (fixedAtList[i].IsActive)
fixedAtList[i].FixedAt();
}
}
}
private void Update() {
if (updateAtList != null) {
for (int i = 0; i < updateAtList.Count; i++) {
if (updateAtList[i].IsActive)
updateAtList[i].UpdateAt();
}
}
}
private void LateUpdate() {
if (lateUpdateAtList != null) {
for (int i = 0; i < lateUpdateAtList.Count; i++) {
if (lateUpdateAtList[i].IsActive)
lateUpdateAtList[i].LateUpdateAt();
}
}
}
void PopulateAllLists() {
fixedAtList = PopulateList<IFixedAt>(GameObjectsWithScripts);
updateAtList = PopulateList<IUpdateAt>(GameObjectsWithScripts);
lateUpdateAtList = PopulateList<ILateUpdateAt>(GameObjectsWithScripts);
}
List<T> PopulateList<T> (List<GameObject> goScripts) {
//Scans the GOs list and adds existent interface elements to the list
var list = new List<T>();
for (int i = 0; i < goScripts.Count; i++) {
if (goScripts[i].GetComponent<T>() != null) {
list.Add(goScripts[i].GetComponent<T>());
}
}
//Returns list (null if list is empty)
if (list.Count > 0) {
return list;
}
else {
return null;
}
}
}
Now, the question for which I'm having trouble in understanding if it's possible to do, and if yes, how.
As you can see, the code inside FixedUpdate, Update and LateUpdate is basically the same: it iterates on the specific List, checks if the current element is active, and if true it executes the proprietary callback.
What I want to know is if it's possible to create a generic method that can be called from inside the three callbacks, and passing to it the List to iterate on and the specific method to call for that List, something like this in pseudo-code:
private void FixedUpdate() {
Method (fixedAtList, FixedAt() );
}
private void Update() {
Method (updateAtList, UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, LateUpdateAt() );
}
private void Method<T> (List<T> list, Action method) {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
list[i].method();
}
}
}
I've tried different things, to no success, and atm I'm clueless about how to do that. Any help will be very appreciated.
First you need an interface that covers the IsActive method.
public interface IActive {
bool IsActive { get; }
}
public interface IFixedAt : IActive {
void FixedAt();
}
public interface IUpdateAt : IActive {
void UpdateAt();
}
public interface ILateUpdateAt : IActive {
void LateUpdateAt();
}
Then you need to use the generic Action<T> and then you can pass in lambdas
private void FixedUpdate() {
Method (fixedAtList, f => f.FixedAt() );
}
private void Update() {
Method (updateAtList, u => u.UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, l => l.LateUpdateAt() );
}
private void Method<T> (List<T> list, Action<T> method) where T : IActive {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
method(list[i]);
}
}
}

Using a List from 2 different threads?

I have a list where it is entries can be updated, new data inserted or removed from 2 different threads.
Is it ok to use a public readonly object to lock when it is being used to interact to the other thread as to when it is locked or not or what would be the correct way to use this list across the 2 threads ?
You should always use a lock when accessing the list on different threads.
public class Sample
{
object synch = new object();
List<Something> list = new List<Something>();
void Add(Something something)
{
lock (synch) { list.Add(something); }
}
// Add the methods for update and delete.
}
You should wrap this in a class that handles the locking for you, or use a thread-safe collection, such as ConcurrentQueue<T> or one of the other collections in System.Collections.Concurrent.
Exposing the synchronization object to a public API is dangerous, and not a good practice.
First, read this article to understand why it's bad: http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx
Then, do it anyway like I did:
public abstract class ConcurrentCollection<T> : ICollection<T>
{
private List<T> List { get; set; }
public ConcurrentCollection()
{
this.List = new List<T>();
}
public T this[int index]
{
get
{
return this.List[index];
}
}
protected virtual void AddUnsafe(T item)
{
this.List.Add(item);
}
protected virtual void RemoveUnsafe(T item)
{
this.List.Remove(item);
}
protected virtual void ClearUnsafe()
{
this.List.Clear();
}
public void Add(T item)
{
lock (this.List)
{
this.AddUnsafe(item);
}
}
public bool Remove(T item)
{
lock (this.List)
{
this.RemoveUnsafe(item);
return true;
}
}
public void Clear()
{
lock (this.List)
{
this.ClearUnsafe();
}
}
public int Count
{
get
{
lock (this.List)
{
return this.List.Count;
}
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool Contains(T item)
{
lock (this.List)
{
return this.List.Contains(item);
}
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (this.List)
{
this.List.CopyTo(array, arrayIndex);
}
}
public IEnumerator<T> GetEnumerator()
{
return new ConcurrentEnumerator<T>(this.List, this.List);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException("Abstract concurrent enumerators not implemented.");
}
}
public class ConcurrentEnumerator<T> : IEnumerator<T>
{
private int Position = -1;
private List<T> Duplicate;
private object Mutex;
private ICollection<T> NonConcurrentCollection;
internal ConcurrentEnumerator(ICollection<T> nonConcurrentCollection, object mutex)
{
this.NonConcurrentCollection = nonConcurrentCollection;
this.Mutex = mutex;
lock (this.Mutex)
{
this.Duplicate = new List<T>(this.NonConcurrentCollection);
}
}
public T Current
{
get
{
return this.Duplicate[this.Position];
}
}
object IEnumerator.Current
{
get
{
return this.Current;
}
}
public bool MoveNext()
{
this.Position++;
lock (this.Mutex)
{
while (this.Position < this.Duplicate.Count && !this.NonConcurrentCollection.Contains(this.Current))
{
this.Position++;
}
}
return this.Position < this.Duplicate.Count;
}
public void Reset()
{
this.Position = -1;
}
public void Dispose() { }
}
// Standards have List as derived Collection...
public class ConcurrentList<T> : ConcurrentCollection<T> { }
This code is still not fully safe, for instance the Count example may still crash, but it allows for iteration, adding and removing across threads. If you want to expose the mutex, do so, then lock around it for your other code constructs like count and contains.
But it's still a bad idea.
Edit: Example usage.
ConcurrentList<string> list = new ConcurrentList<string>();
list.Add("hello");
list.Add("world");
list.Add("foo");
list.Add("bar");
foreach (string word in list)
{
if (word == "world")
{
list.Remove("bar"); // Will not crash the foreach!
}
Console.WriteLine(word);
}
Output:
hello
world
foo

BindingList not updating bound ListBox

I have a ListBox that is bound to a BindingList. The BindingList is built up when a third party application raises an event. I can see the BindingList being bound correctly... but nothing enters the ListBox. I have used the exact same logic with some of my own custom types and it usually works very well.
Form class
private Facade.ControlFacade _controlFacade;
public UavControlForm()
{
InitializeComponent();
_controlFacade = new UavController.Facade.ControlFacade();
UpdateEntityListBox();
}
private void UpdateEntityListBox()
{
lsbEntities.DataSource = _controlFacade.GetEntityTally();
lsbEntities.DisplayMember = "InstanceName";
}
Facade class
private Scenario _scenario;
public ControlFacade()
{
_scenario = new Scenario();
}
public BindingList<AgStkObject> GetEntityTally()
{
BindingList<AgStkObject> entityTally = _scenario.EntityTally;
return entityTally;
}
Scenario class
private static BindingList<IAgStkObject> _entityTally = new BindingList<AgStkObject>();
public Scenario()
{
if (UtilStk.CheckThatStkIsAvailable())
{
UtilStk.StkRoot.OnStkObjectAdded += new IAgStkObjectRootEvents_OnStkObjectAddedEventHandler(TallyScenarioObjects);
UtilStk.StkRoot.OnStkObjectDeleted += new IAgStkObjectRootEvents_OnStkObjectDeletedEventHandler(TallyScenarioObjects);
}
}
private void TallyScenarioObjects(object sender)
{
List<AgStkObject> tallyOfStkObjects = UtilStk.GetRunningTallyOfAllStkObjects();
List<string> stkObjectNames = UtilStk.GetInstanceNamesOfStkObjects(tallyOfStkObjects);
foreach (string stkObjectName in stkObjectNames)
{
if (!SearchFlightUavTallyByName(stkObjectName))
{
if (!SearchLoiterUavTallyByName(stkObjectName))
{
if (!SearchEntityTallyByName(stkObjectName))
{
int i = stkObjectNames.IndexOf(stkObjectName);
_entityTally.Add(tallyOfStkObjects[i]);
}
}
}
}
}
I can see the event fire from the third-party application - this adds an entity to _entityList as desired, but noothing is added to lsbEntities - why?
(jump right to the last example if you want to see it fixed etc)
Threads and "observer" patterns (such as the data-binding on winforms) are rarely good friends. You could try replacing your BindingList<T> usage with the ThreadedBindingList<T> code I used on a previous answer - but this combination of threads and UI is not an intentional use-case of winforms data-binding.
The listbox itself should support binding via list notification events (IBindingList / IBindingListView), as long as they arrive form the right thread. ThreadedBindingList<T> attempts to fix this by thread-switching on your behalf. Note that for this to work you must create the ThreadedBindingList<T> from the UI thread, after it has a sync-context, i.e. after it has started displaying forms.
To illustrate the point that listbox does respect list-change notifications (when dealing with a single thread):
using System;
using System.ComponentModel;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
using (var timer = new Timer())
{
var data = new BindingList<Foo>();
form.Controls.Add(lst);
lst.DataSource = data;
timer.Interval = 1000;
int i = 0;
timer.Tick += delegate
{
data.Add(new Foo(i++));
};
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
timer.Start();
};
Application.Run(form);
}
}
}
and now with added threading / ThreadedBindingList<T> (it doesn't work with the regular BindingList<T>):
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
{
form.Controls.Add(lst);
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
BindingList<Foo> data = new ThreadedBindingList<Foo>();
lst.DataSource = data;
ThreadPool.QueueUserWorkItem(delegate
{
int i = 0;
while (true)
{
data.Add(new Foo(i++));
Thread.Sleep(1000);
}
});
};
Application.Run(form);
}
}
}
public class ThreadedBindingList<T> : BindingList<T>
{
private readonly SynchronizationContext ctx;
public ThreadedBindingList()
{
ctx = SynchronizationContext.Current;
}
protected override void OnAddingNew(AddingNewEventArgs e)
{
SynchronizationContext ctx = SynchronizationContext.Current;
if (ctx == null)
{
BaseAddingNew(e);
}
else
{
ctx.Send(delegate
{
BaseAddingNew(e);
}, null);
}
}
void BaseAddingNew(AddingNewEventArgs e)
{
base.OnAddingNew(e);
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (ctx == null)
{
BaseListChanged(e);
}
else
{
ctx.Send(delegate
{
BaseListChanged(e);
}, null);
}
}
void BaseListChanged(ListChangedEventArgs e)
{
base.OnListChanged(e);
}
}

Categories

Resources