is it possible to set a Datasource through a reference?
public partial class GraphView : UserControl
{
public ObservableCollection<ChartCollection<long>> signals { get; set; }
public GraphView()
{
UCGraph.DataSource = this.signals;
}
}
and if I set the signals property should it update the Datasource?
MyGraphUC.signals = mySignals;
It doesn't seem to be working for me. Why?
No you can't directly because the variables UCDataGraph.DataSource and signals are not connected by any means. They just happen to point to the same instance after you assign them in your constructor (actually they will both point to null which is not an instance at all). That being said, you can leverage the setter to do your bidding like so:
public partial class GraphView : UserControl
{
private ObservableCollection<ChartCollection<long>> _signals
public ObservableCollection<ChartCollection<long>> signals
{
get
{
return _signals;
}
set
{
this._signals = value;
UCGraph.DataSource = this._signals;
}
}
public GraphView()
{
UCGraph.DataSource = this.signals;
}
}
Alternatively you can just .Clear() the observable collection and refill it with the elements instead of changeing the collection itself if that is an feasible scenario for you.
Related
I'm creating a WinForms application with a DataGridView. The DataSource is a ReactiveList. Adding new items to the list however does not update the UI.
ViewModel
public class HomeViewModel: ReactiveObject
{
public ReactiveCommand<object> AddCmd { get; private set; }
ReactiveList<Model> _models;
public ReactiveList<Model> Models
{
get { return _models; }
set { this.RaiseAndSetIfChanged(ref _models, value); }
}
public HomeViewModel()
{
Models = new ReactiveList<Model>() { new Model { Name = "John" } };
AddCmd = ReactiveCommand.Create();
AddCmd.ObserveOn(RxApp.MainThreadScheduler);
AddCmd.Subscribe( _ =>
{
Models.Add(new Model { Name = "Martha" });
});
}
}
public class Model
{
public string Name { get; set; }
}
View
public partial class HomeView : Form, IViewFor<HomeViewModel>
{
public HomeView()
{
InitializeComponent();
VM = new HomeViewModel();
this.OneWayBind(VM, x => x.Models, x => x.gvData.DataSource);
this.BindCommand(VM, x => x.AddCmd, x => x.cmdAdd);
}
public HomeViewModel VM { get; set; }
object IViewFor.ViewModel
{
get { return VM; }
set { VM = (HomeViewModel)value; }
}
HomeViewModel IViewFor<HomeViewModel>.ViewModel
{
get { return VM; }
set { VM = value; }
}
}
The view always show "John".
Debugging Subscribe show added items.
Tried it with ObservableCollection same result.How to use ReactiveList so UI is updated when new items are added
Tried it with IReactiveDerivedList same result. Does ReactiveUI RaiseAndSetIfChanged fire for List<T> Add, Delete, Modify?
I think what you want is a ReactiveBindingList rather than a ReactiveList. This is a WinForms specific version of the ReactiveList for binding purposes.
You should use BindingList.
reference :
"If you are bound to a data source that does not implement the IBindingList interface, such as an ArrayList, the bound control's data will not be updated when the data source is updated. For example, if you have a combo box bound to an ArrayList and data is added to the ArrayList, these new items will not appear in the combo box. However, you can force the combo box to be updated by calling the SuspendBinding and ResumeBinding methods on the instance of the BindingContext class to which the control is bound."
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-bind-a-windows-forms-combobox-or-listbox-control-to-data?view=netframeworkdesktop-4.8
Or
ReactiveBindingList
It work fine for me. !!!
I'm working on adding a Windsor IoC container to an existing WinForms application that uses an MVP UI design pattern. I'm trying to determine a good approach to resgistering a datacontext that depends on a connection string supplied at runtime. The problem is that I cannot create a datacontext until the user selects a database, i.e. a 'connection string' after the application has loaded. Granted only one datacontext is generally used, but sometimes a user need to switch to a different database, i.e. creating a differnet datacontext. This leads to additional runtime dependencies as well.
public interface IProductsView
{
event EventHandler<ProductSelectedEventArgs> ProductSelectedEvent;
event EventHandler<StringEventArgs> ProductStatusEvent;
void ClearProductList();
void DisplayProductList(IList<Product> products);
Control Control { get; }
IProductsPresenter Presenter { get; set; }
}
public class ProductsPresenter : IProductsPresenter
{
public IProductsView View { get; set; }
private IProductRepository Repository { get; set; }
public ProductsPresenter(IProductsView view, IProductRepository repository)
{
View = view;
View.Presenter = this;
Repository = repository;
}
public void ProductSelected(IList<Product> products)
{
throw new NotImplementedException();
}
public void ShowProductList(string name)
{
IList<Product> productList;
if (string.IsNullOrEmpty(name))
productList = Repository.GetProducts();
else
productList = Repository.GetProductsByName(name);
View.DisplayProductList(productList);
}
}
public class ProductDao : IDisposable, IProductRepository
{
private MeasurementDataContext dataContext;
public ProductDao(MeasurementDataContext context)
{
dataContext = context;
}
public List<Product> GetProducts()
{
return dataContext.Products.Select(p => Mapper.Map(p)).ToList().OrderBy(x => x.Name).ToList();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (dataContext != null)
{
dataContext.Dispose();
dataContext = null;
}
}
~ProductDao()
{
this.Dispose(false);
}
}
So this means that the Presenter in my View is null until the IProductRepository is created, which in turn depends on creating a MeasurementDataContext. I have these component regisitered in a IWindsorInstaller like so:
container.Register(Component.For<IProductsView>()
.ImplementedBy<ViewProductsControl>());
container.Register(Component.For<IProductsPresenter>()
.ImplementedBy<ProductsPresenter>());
Do I need to use Named and DependsOn which supply a unique name and connectionString argument for each datacontext?
What I currently do to register the data context at runtime after the user has selected a database
kernel.Register(Component.For<MeasurementDataContext>()
.UsingFactoryMethod(() => new MeasurementDataContext(conn)));
and then `Resolve' my Views and set their Presenters. I know this is not good design, but it's a brute force way of resolving my dependcies.
Thanks
UPDATE:
I changed the way I registered my datacontext's in the installer to the following:
container.Register(Component.For<DataContext>().ImplementedBy<MeasurementDataContext>().Named("Localhost").DependsOn(new { connectionString = conn }));
and then modified my model's constructor to:
public ProductDao(DataContext context)
{
dataContext = context as MeasurementDataContext;
}
All components will resolve with the right key:
kernel.Resolve<DataContext>(cbo.SelectedItem.ToString());
What about injecting a wrapper class to hold the connection string and have the datacontext objects use that? Something along these lines:
public class ConnectionStringProvider : IConnectionStringProvider
{
private string _value;
public event EventHandler ConnectionStringChanged;
public string ConnectionString
{
get { return _value; }
set
{
_value = value;
var del = ValueChanged;
if (del != null)
del(this, EventArgs.Empty);
}
}
}
Register this with and singleton lifestyle. This way your application can set or update the connection string on a single object and everyone who depends on it will be notified of the change.
I have often run into situations where I want to have a 3-State checkbox to select all/deselect all of my view models. I have run into difficulties creating a reusable class to do this with.
I tried to create the following base classes:
public class SelectAllListVM
{
public List<SelectableVM> ChildList = new List<SelectableVM>();
public bool? SelectAll // call UpdateSelectedChildren on set
internal void UpdateSelectAll ()
// Set SelectAll based on ChildList elements
// true = all selected, false = non selected, null = some selected
private void UpdateSelectedChildren () {
foreach ( SelectableVM vm in ChildList )
vm.SetIsSelected( SelectAll.Value );
}
}
public class SelectableVM
{
public SelectableVM (SelectAllListVM parentVM) {}
public bool IsSelected // call parentVM.UpdateSelectAll
}
The problem with this is every time I want to iterate through the ChildList I have to cast the SelectableVM to it's concrete implementation. How can I reuse this behavior and avoid casting?
I did some attached behavior trickery back in the day to do this. Everything is handled by the view no need for the VM to care about select all logic. I wrote the details of how to do it in three parts (part 1, part 2, part 3) I made the code available on fileden...and subsequently lost it because I didn't log into the account enough times. But all the code is there throughout the three posts.
You could create an Interface ISelectableVM
public interface ISelectableVM
{
public bool IsSelected;
}
and implement it in your derived classes.
public class SelectableVM : ISelectableVM
{}
public class OtherSelectableVM : ISelectableVM
{}
Then in your ParentVM you don't have to cast:
public class SelectAllListVM
{
public List<ISelectableVM> ChildList = new List<ISelectableVM>();
public bool? SelectAll; // call UpdateSelectedChildren on set
private void UpdateSelectedChildren()
{
foreach (ISelectableVM vm in ChildList)
vm.IsSelected = SelectAll.Value;
}
}
Instead of an interface you could also use
public class BaseSelectableVM
{
public bool IsSelected;
}
and derive from it.
I'm not sure the best way to get this accomplished. Here's my view:
public partial class MyPage : Page
{
[Import]
public MyVM ViewModel
{
get { return DataContext as MyVM ; }
set { DataContext = value; }
}
public String EventName { get; set; }
public MyPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{ }
}
And my VM:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ()
{
}
}
This works great. However, I need to get data from either the viewmodel that has my string, or the URL. Either way, I'm not sure the best way to get the string to MyVW using MEF.
I thought ok I'll use Messaging from MVVMLight, but the MyVM class isn't instantiated yet to receive the broadcast from the other ViewModel. So then I thought well, I'll try this:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ([Import("hello")]string hello)
{
}
}
and then put this in the view:
[Export("hello")]
public String MyHello { get; set; }
but that gave me an error. Cannot call SatisfyImports on a object of type 'Form A' because it is marked with one or more ExportAttributes.
So what's the best way to accomplish this?
To share data between views I usually inject a SharedData object into my ViewModels.
[Import(RequiredCreationPolicy = CreationPolicy.Shared)]
public ISharedData SharedData { get; set; }
I'm also using the Caliburn Micro framework so I'm not passing data around via the URL querystring. By convention CM will parse out URL parameters and inject them into properties on your VM but I'm not sure if this functionality only applies to Windows Phone development.
from here
Examine the Page’s QueryString. Look
for properties on the VM that match
the QueryString parameters and inject
them, performing the necessary type
coercion.
When you say you want to possibly pass data from the view to the vm, that should happen through databinding.
I'm currently trying to create a small application using the MVVM pattern. However I don't really know how to correctly wrap up aggregated Model classes in my ViewModel. From what little I know about MVVM, you're not supposed to expose Models in your ViewModel as properties or else you could directly bind to the Model from your View. So it seems I have to wrap the nested Model in another ViewModel, but this imposes some problems while synching Model and ViewModel later on.
So how do you do that efficiently?
I'll give a short example. Let's suppose I have the following model classes:
public class Bar
{
public string Name { get; set; }
}
public class Foo
{
public Bar NestedBar { get; set; }
}
Now I create two ViewModel classes accordingly, wrapping the Models, but run into problems with the FooViewModel:
public class BarViewModel
{
private Bar _bar;
public string Name
{
get { return _bar.Name; }
set { _bar.Name = value; }
}
}
public class FooViewModel
{
private Foo _foo;
public BarViewModel Bar
{
get { return ???; }
set { ??? = value; }
}
}
Now what do I do with the Bar-property of FooViewModel? For "get" to work I need to return a BarViewModel instance. Do I create a new field of that type in FooViewModel and just wrap the _foo.NestedBar object in there? Changes to that field's properties should propagate down to the underlying Bar instance, right?
What if I need to assign another BarViewModel instance to that property, like so:
foo.Bar = new BarViewModel();
Now that won't propagate down to the model, which still holds the old instance of type Bar. I'd need to create a new Bar object based on the new BarViewModel and assing it to _foo, but how do you do that elegantly? It's pretty trivial in this sample, but if Bar is much more complex with lots of properties, that'll be a lot of typing... not to mention it'd be very prone to errors, if you forget to set one of the properties.
#Goblin
There are some flaws with your code: e.g. what if I get a list of Foo objects from database and I want to wrap each of them in an ObservableCollection?
then your Constructor of FooViewModel should accept the Foo model as parameter and not create it inside the Constructor!
Normally you do this to wrap a model into a viewmodel and put it the same time into a bindable Collection:
IEnumerable<Foo> foos = fooRepository.GetFoos();
foos.Select( m => viewmodelCollection.Add(new ViewModel(m,e.g.Service)));
The models properties are not copied to the ViewModel hell no!!! The ViewModel does delegate its properties to the model properties like:
public class FooViewModel
{
private Foo _foo;
public FooViewModel(Foo foo,IService service)
{
_foo = foo;
}
public string FoosName
{
get{return _foo.Name };
set
{
if(_foo.Name == value)
return;
_foo.Name = value;
this.NotifyPropertyChanged("FoosName");
}
}
}
And like Goblin said all UI-Specific interfaces like:
IDataErrorInfo
INotifyPropertyChanged
IEditableObject
etc...
are implemented the by the ViewModel ONLY.
My above answer only makes sense if you are doing DDD - if you are not - you can solve your problem like this - simply 'flattening' the model:
public class FooViewModel
{
private Foo _foo;
public string Name
{
get { return _foo.Name; }
set { _foo.Name = value; }
}
public string BarProperty
{
get { return _foo.Bar.Property; }
set { _foo.Bar.Property = value; }
}
}
Or you could do like I showed in the prior example - just ignore everything about Aggregates... should still work.
Okay - first things first - using the term Aggregate implies you are adhering to DDD? If you are - you are doing an encapsulation no-no :-). One Aggregate should never be allowed to edit another Aggregate. If what you have is that both are really Aggregate they would become associated (which is perfectly 'legal' in a DDD-sense - but then your propety on the FooViewModel wouldn't be of type BarViewModel, but rather type Bar. That way Bar would (as it should) be responsible for updating itself - and we only maintain the link in FooViewModel.
However, if what you are doing is AggregateRoot with a ValueType child - then here is what you could do given a slightly modified domain model:
public class Foo
{
public string SomeProperty { get; set; }
public Bar Bar { get; set; }
public void Save()
{
//Magically saves to persistent storage...
}
}
public class Bar
{
public Bar(string someOtherProperty)
{
SomeOtherProperty = someOtherProperty;
}
public string SomeOtherProperty { get; private set; }
}
And then for the ViewModels:
public class FooViewModel
{
private Foo _foo;
public FooViewModel()
{
Bar = new BarViewModel();
}
public BarViewModel Bar { get; private set; }
public void SetFoo(Foo foo)
{
_foo = foo;
SomeProperty = foo.SomeProperty;
Bar.SetBar(foo.Bar);
}
public string SomeProperty { get; set; }
public void SaveChanges()
{
_foo.SomeProperty = SomeProperty;
_foo.Bar = Bar.CreateUpdatedBar();
_foo.Save();
}
}
public class BarViewModel
{
public string SomeOtherProperty { get; set; }
public void SetBar(Bar bar)
{
SomeOtherProperty = bar.SomeOtherProperty;
}
public Bar CreateUpdatedBar()
{
return new Bar(SomeOtherProperty);
}
}
This way - the FooViewModel is now capable of controlling the BarViewModel (which does nothing but accept a valuetype - and create a new one when asked). This also solves a common UI-problem ('How do we edit an object that has no setters?' - answer: 'We don't - we create a new one'). A lot of fleshing out is missing (INotifyPropertyChanged, dirty-tracking etc., but those are easy if you get through this leap of thinking :-).
I hope this makes a wee bit of sense :-) Otherwise, I'll be happy to elaborate.