Please excuse my ignorance for I am new to C#.
I am currently working on an MVVM project in which a viewmodel has multiple instantiated public variables that are data-bound to elements in a view (WPF). When these variables are changed they automatically update in my view. Take for instance the code segment below from my view model...
private string _displaybind;
public string DisplayBind
{
get { return _displaybind; }
set
{
SetProperty(ref _displaybind, value);
if (_displaybind.Length > 5000)
{
DisplayBind = _displaybind.Substring(_displaybind.IndexOf('\n') + 1);
}
}
}
By using the command DisplayBind = "Hello"; within my viewmodel I can push out text to a textbox I have located in my XAML view. Unfortunately, I have reached a point where I can not simply edit the value of DisplayBind.
I need to start a state machine within my viewmodel which will access several states (classes) in separate C# files. However, I have no idea how to receive, and more importantly edit the values within my viewmodel from these separate classes.
I start my state machine in my viewmodel using this...
IPMProgram ipmprogram = new IPMProgram();
ipmprogram.StartTheIPMProgram();
This is my IPMProgram class
public class IPMProgram
{
public IPMProgramState currentState = null;
public IPMProgram()
{
currentState = new BootBannerState(this);
}
public void StartTheIPMProgram()
{
while (true)
{
currentState.GetNextState();
}
}
}
This is my IPMProgramState class
public abstract class IPMProgramState
{
private IPMProgram ipmprogram;
public IPMProgram Ipmprogram
{
get { return ipmprogram; }
set { ipmprogram = value; }
}
public abstract void GetNextState();
}
And this is my BootBannerState class (The state I want to edit DisplayBind from)
class BootBannerState : IPMProgramState
{
public BootBannerState(IPMProgramState state)
:this(state.Ipmprogram)
{
}
public BootBannerState(IPMProgram ipmprograminstance)
{
this.Ipmprogram = ipmprograminstance;
}
public override void GetNextState()
{
//DisplayBind = "Hello"!
return;
}
}
Someone suggested that I should look into Dependency Injection, but I don't quite understand how it would work for me. What should I do?
Thank you for all of your help,
Tesnich
In C#, I have a suffiently complex Model. I already have a WPF Client to manipulate that model. I'm using MVVM. All objects in that model support INotifyPropertyChanged and all properties that are collections support INotifyCollectionChanged.
Take this as a simplied example:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace CollectionTest1
{
public class PropertyChangedSupport : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Company : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<Employee> Employees { get; } = new ObservableCollection<Employee>();
}
public class Employee : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<PresentTimespan> PresentTimespans { get; } = new ObservableCollection<PresentTimespan>();
public Boolean IsPresentAt(DateTime t)
{
foreach (PresentTimespan pt in PresentTimespans)
{
if (pt.Start.CompareTo(t) <= 0 && pt.Finish.CompareTo(t) >= 0) return true;
}
return false;
}
}
public class PresentTimespan : PropertyChangedSupport
{
private string comment;
public String Comment { get { return comment; } set { comment = value; FirePropertyChange(); } }
private DateTime start;
public DateTime Start { get { return start; } set { start = value; FirePropertyChange(); } }
private DateTime finish;
public DateTime Finish { get { return finish; } set { finish = value; FirePropertyChange(); } }
}
public class CompanyStatusView : PropertyChangedSupport
{
private DateTime currentTime;
public DateTime CurrentTime { get { return currentTime; } set { currentTime = value; FirePropertyChange(); } }
private Company currentCompany;
public Company CurrentCompany { get { return currentCompany; } set { currentCompany = value; FirePropertyChange(); } }
public ObservableCollection<Employee> PresentEmployees { get; } = new ObservableCollection<Employee>();
public CompanyStatusView()
{
UpdatePresentEmployees();
}
private void UpdatePresentEmployees()
{
PresentEmployees.Clear();
foreach (Employee e in CurrentCompany.Employees) {
if (e.IsPresentAt(currentTime)) PresentEmployees.Add(e);
}
}
}
}
I'd like to have UpdatePresentEmployees called whenever there are changes in:
Collection Company.Employees.PresentTimespans
Property Company.Employees.PresentTimespans.Start
Property Company.Employees.PresentTimespans.Finish
Collection Company.Employees
Property CurrentTime
Property CurrentCompany
So it's basically any property or collection read by UpdatePresentEmployees.
My best solution so far included registering a lot of event handlers to all the objects mentioned above. That included to have a couple of Dictionary instances to track which added objects I have to subscribe to and especially which I have to unsubscribe from.
The most difficult and annoying part was to subscribe to all the PresentTimespan objects to listen for property changes and all the PresentTimespans collections of Employee to listen for collection changes.
My guess is that there has to be a better way to do this.
After all, in JFace (Java) there is a very interesting solution that uses ObservableTracker. So there you'd only provide the code for UpdatePresentEmployees and ObservableTracker tracks which objects have been read and automatically makes you listen for changes in any of these and also correctly unsubscribes from irrelevant objects. So there are better approaches to this problem in general. What is C# offering? Can it do better than my best solution I mentioned above? Can I avoid some of the boilerplate code? Can it be done with .net provided classes or do I need some additional classes/libraries?
Thanks for your kind help and advice in advance!
You could use BindingList instead of ObservableCollection and attach to the the ListChanged Event. But keep in mind that BindingList has some disadvantages like not being very fast. For further information this could be interesting: difference between ObservableCollection and BindingList
If you dont wanna use BindingList you have to wire your items with events.
As pointed out by Nikhil Agrawal, Rx or ReactiveUI is a good framework for my purpose. So I consider that to be a solution.
I am working on small winforms app. One of my forms contains few comboBoxes:
As I am trying to use MVP pattern in my project, so I decided to create View and Presenter for that form. The communicate via adequate interface.
ComboBox can be fully decribed (for my needs) with its DataSource (i.e. list os strings) and SelectedIndex. That' s why I created proper interface:
public interface IMyView
{
MyViewPresenter { set; }
IEnumerable<string> ComboBox1stDataSource { get; set; }
int ComboBox1SelectedIndex { get; set; }
IEnumerable<string> ComboBox2ndDataSource { get; set; }
int ComboBox2ndSelectedIndex { get; set; }
//for third comboBox it will be the same
}
I implemented that interface in my View class:
public partial class MaterialDatabasePropertiesForm : Form, IMaterialDatabasePropertiesView, IMyView
{
public MaterialDatabasePropertiesPresenter Presenter { private get; set; }
public IEnumerable<string> ComboBox1stDataSource
{
get { return comboBox1st.DataSource as List<string>; }
set { comboBox1st.DataSource = value; }
}
public int ComboBox1SelectedIndex
{
get { return comboBox1st.SelectedIndex; }
set { comboBox1st.SelectedIndex = value; }
}
public IEnumerable<string> ComboBox2ndDataSource
{
get { return comboBox2nd.DataSource as List<string>; }
set { comboBox2nd.DataSource = value; }
}
public int ComboBox2ndSelectedIndex
{
get { return comboBox2nd.SelectedIndex; }
set { comboBox2nd.SelectedIndex = value; }
}
}
When everything is set like above I use properties declared in Interface in my Presenter to change properties of comboBoxes in form.
Although it may seem like a good solution it isn' t enough for me. In my origial application I have 14 comboBoxes, and that number may change in future.
What I am trying to is making it more elastic. I was thinking about creatin some collection of comboBoxes in view, but I can' t figure it out.
My sample solutin is bad, as it doesn' t even compile:
private List<List<string>> collectionOfComboBoxesDataSources = new List<List<string>>()
{
ref comboBox1st.DataSource, // I get error:
ref comboBox2nd.DataSource, // "Cannot acces non-static field
ref comboBox3rd.DataSource // <comboBoxName> in static context"
};
//this property would be part of IMyView
public List<List<string>> CollectionOfComboBoxesDataSources
{
get { return collectionOfComboBoxesDataSources; }
set { collectionOfComboBoxesDataSources = value; }
}
What can I do to create collection (or something working similar) to acces my comboBoxes properties?
You could try to iterate through your form.
List<ComboBox> listOfCombobox = new List<ComboBox>();
foreach(var combobox in this.controls.OfType<ComboBox>())
{
listOfCombobox.Add(combobox);
}
If you're trying to do this.
Then you can access the list via index, so you can access your properties of each combobox.
Let's say that I got a simple todolist:
interface ITodoList
{
ITodoItem Create(title);
IEnumerable<ITodoItem> Items {get;}
}
interface ITodoITem
{
void StartTrackTime();
void StopTrackTime();
}
Now I want to enforce so that time is only tracked for one item at a time (per user).
Should I create a domain event like ItemTimeTrackingStarted that StartTrackTime generates. The event would be picked up by a ITodoService which checks if there are any other time tracked items for the current user (and stop them). Or are there a better way?
well if you have dependencies between the items, which in the case is the check, my proposal would be to move the track method into the todo list object, and away from item.
So you request a change from the object that holds all todo items, and there you locate the checks as well.
IMO I'd do it like this, I don't know all the details of the context, but for this specific functionality here it goes
public interface ITrackTime
{
void StartTrackTime();
void StopTrackTime();
}
public interface ITodoItem
{
int Id {get;}
//other stuff
}
public TodoItem:ITodoITem, ITrackTime {}
public class TodoList:ITodoList,ITrackItem
{
ITodoItem Create(title)
{
//create item and add it to collection
}
TodoItem _currentlyTracking;
void StartTrackTime(int itemId)
{
if (_currentlyTracking == null)
{
// getItem and call method for item ..
item.StartTrackTime();
_currentlyTracking=item;
}
else{
//get item and check to see if it is the same id
//throw exception if it is not, ignore it if it is
}
}
}
var list = new TodoList();
ITodoItem item= list.Create("titel");
list.StartTrackingTime(item.Id);
list.StartTrackingTime(otherId); //should throw or whatever handling
Everything is contained within the AR (TodoList). One again, this is a rough draft as I'm not fully aware about the context and the domain.
As stated, the ToDoList should enforce the constraint since the constraint is defined at the ToDoList level. (Unless it is defined at the user level as you indicated in which case the responsibility would shift there). You can leave the method on the item, but it can reference the parent todo list. The code could look like this:
public class ToDoList
{
public IList<ToDoListItem> Items { get; private set; }
// factory method creates items as required by ToDoList
public ToDoListItem Create(string title)
{
var item = new ToDoListItem(this, title);
this.Items.Add(item);
return item;
}
ToDoListItem currentItem;
public void StartTrackTimeFor(ToDoListItem item)
{
if (this.currentItem != null)
throw new Exception();
// could also throw different exception if specified item is current item being tracked
// start time tracking logic.
this.currentItem = item;
}
public void StopTrackTimeFor(ToDoListItem item)
{
if (this.currentItem != item)
throw new Exception();
// stop time tracking logic.
this.currentItem = null;
}
}
public class ToDoListItem
{
public ToDoListItem(ToDoList list, string title)
{
this.ToDoList = list;
this.Title = title;
}
public ToDoList ToDoList { get; private set; }
public string Title { get; private set; }
public void StartTrackTime()
{
this.ToDoList.StartTrackTimeFor(this);
}
public void StopTrackTime()
{
this.ToDoList.StopTrackTimeFor(this);
}
}
I need to refactor the following class:
public interface IEmployee
{
int VacationWeeks { get; }
int YearsWithCompany { set; get; }
double Salary { set; get; }
}
public class Employee : IEmployee
{
private readonly int vacationWeeks;
public Employee(int vacationWeeks)
{
this.vacationWeeks = vacationWeeks;
}
public int VacationWeeks
{
get { return vacationWeeks; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
I need to make sure that VacationWeeks depends only on YearsWithCompany, and I am loading the mapping from the database. So far I have come up with this:
public class EmployeeNew : IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
public EmployeeNew(Dictionary<int, int> vacationWeeksTable)
{
this.vacationWeeksTable = vacationWeeksTable;
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
This class implements what I want, but it still has one vulnerability: different instances of EmployeeNew in the same collection may have been created with different instances of vacationWeeksTable.
All instances of EmployeeNew in the same collection must refer to the same vacationWeeksTable.
The application I am refactoring uses lots of List all over the system, and we need to be able to modify YearsWithCompany and Salary, yet to guarantee that only one vacationWeeksTable is used per List. These lists are iterated several times; its elements are modified in each iteration.
Here is my imperfect solution. Suggestions are welcome:
// this class does two things, which I do not like
public class EmployeeList : IEnumerable<IEmployee>, IEmployee
{
private Dictionary<int, int> vacationWeeksTable;
private List<EmployeeSpecificData> employees;
private int currentIndex;
private EmployeeSpecificData CurrentEmployee
{
get { return employees[currentIndex]; }
}
public IEnumerator<IEmployee> GetEnumerator()
{
for (currentIndex = 0; currentIndex < employees.Count; currentIndex++)
{
yield return this;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
// this is ugly repetitive code I don't like
public int YearsWithCompany
{
get { return CurrentEmployee.YearsWithCompany; }
set { CurrentEmployee.YearsWithCompany = value; }
}
// this is ugly repetitive code I don't like
public double Salary
{
get { return CurrentEmployee.Salary; }
set { CurrentEmployee.Salary = value; }
}
}
I use the following to create and init some of the classes that need default and shared behaviour. Maybe if you can refactor it will help:
It is some form of the Factory and FlyWeight patterns combined (the flyweight part can be removed in your scenario), which in addition has a concept of class Type shared handlers.
I simplified and removed some stuff that you wont need but there is more to remove, I added comments.
Usage would be: (app init)
Dictionary<int,int> vacationWeeksTable = new Dictionary<int,int>();
// fill the table
Factory<Employee>.Init(vacationWeeksTable);
The whenever you create a Employee class:
// remove grouping in the factory class to remove this null
Employee em = Factory<Employee>.Create(null);
It takes only a WeakReference to the classes so you don't have to worry about GC.
Each employee will have the shared vacationWeeksTable setup on creation, without the possibility to change it after from outside if not using the factory class.
You could change the vacation table for all running instances of Employee at any moment in the runtime of the app with:
// this will call the method registered for SetInitialdata on all instances of Employee classes.
// again remove grouping to remove that null
Factory<Employee>.Call(EventHandlerTypes.SetInitialData, null, vacTable);
Sample implementation of Employee:
class Employee : IBaseClass
{
private Dictionary<int, int> vacationWeeksTable;
public virtual void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> register)
{
group = 0; // disable different groups
register(new Key<Employee, int>(0), group, EventHandlerTypes.SetInitialData, SetVacationWeeksTable);
}
public virtual void RegisterSharedData(Action<IKey, object> regData)
{
// remove this from factory and interface, you probably dont need it
// I have been using it as a FlyWeight data store for classes.
}
private void SetVacationWeeksTable(object sender, SharedEventArgs e)
{
vacationWeeksTable = e.GetData<Dictionary<int, int>>();
}
}
Code pattern Implementation:
IBaseClass : interface that each of my classes that are creatable through a factory implement
public enum EventHandlerTypes
{
SetInitialData // you can add additional shared handlers here and Factory<C>.Call - it.
}
public class SharedEventArgs : EventArgs
{
private object data;
public SharedEventArgs(object data)
{
this.data = data;
}
public T GetData<T>()
{
return (T)data;
}
}
public interface IBaseClass
{
void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> regEvent);
void RegisterSharedData(Action<IKey, object> regData);
}
Utility generic classes:
public interface IKey
{
Type GetKeyType();
V GetValue<V>();
}
public class Key<T, V> : IKey
{
public V ID { get; set; }
public Key(V id)
{
ID = id;
}
public Type GetKeyType()
{
return typeof(T);
}
public Tp GetValue<Tp>()
{
return (Tp)(object)ID;
}
}
public class Triple<T, V, Z>
{
public T First { get; set; }
public V Second { get; set; }
public Z Third { get; set; }
public Triple(T first, V second, Z third)
{
First = first;
Second = second;
Third = third;
}
}
Factory class with slight modification to handle your scenario:
public static class Factory<C> where C : IBaseClass, new()
{
private static object initialData;
private static Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>> handlers = new Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>>();
private static Dictionary<IKey, object> data = new Dictionary<IKey, object>();
static Factory()
{
C newClass = new C();
newClass.RegisterSharedData(registerSharedData);
}
public static void Init<IT>(IT initData)
{
initialData = initData;
}
public static Dt[] GetData<Dt>()
{
var dataList = from d in data where d.Key.GetKeyType() == typeof(Dt) select d.Value;
return dataList.Cast<Dt>().ToArray();
}
private static void registerSharedData(IKey key, object value)
{
data.Add(key, value);
}
public static C Create(int? group)
{
C newClass = new C();
newClass.RegisterSharedHandlers(group, registerSharedHandlers);
// this is a bit bad here since it will call it on all instances
// it would be better if you can call this from outside after creating all the classes
Factory<C>.Call(EventHandlerTypes.SetInitialData, null, initialData);
return newClass;
}
private static void registerSharedHandlers(IKey subscriber, int? group, EventHandlerTypes type, Action<object, SharedEventArgs> handler)
{
handlers.Add(subscriber, new Triple<EventHandlerTypes, int, WeakReference>(type, group ?? -1, new WeakReference(handler)));
}
public static void Call<N>(EventHandlerTypes type, int? group, N data)
{
Call<N>(null, type, group, data);
}
public static void Call<N>(object sender, EventHandlerTypes type, int? group, N data)
{
lock (handlers)
{
var invalid = from h in handlers where h.Value.Third.Target == null select h.Key;
// delete expired references
foreach (var inv in invalid.ToList()) handlers.Remove(inv);
var events = from h in handlers where h.Value.First == type && (!#group.HasValue || h.Value.Second == (int)#group) select h.Value.Third;
foreach (var ev in events.ToList())
{
// call the handler
((Action<object, SharedEventArgs>)ev.Target)(sender, arg);
}
}
}
}
Make a class which contains a Dictionary. Creating or getting instance of this new class will load the dictionary in a consistent way. Then your BOs can take an instance of the class, thus ensuring they're all using the same data (because the class containingthe list knows how to load itself with the proper set of data).