Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm starting using ReactiveUI in some projects; I still have some difficult to understand some core concepts and I don't know how to manage some common scenario, what are best practices.
Suppose I created a TextEditor which expose a TextChanged event. I manage to create an observable named "CanSave" attached to this event which emit true when user write something;
Now I can use "CanSave" as "canexecute" property of a Save command. This works but, when user click Save, "CanSave" should now emit false because user already saved his work!
How is supposed to manage situations like this? I figured out to create a CanSave settable property and subscribe it to changed event, then observe CanSave property .. is this the correct way?
You're nearly there, or maybe your terminology and description is misleading me.
You need some sort of an Iobservable IsDirty ( or CanSave ) which you can use as a canexecute.
This should be true when a significant change has been made but not saved.
You want to observe TextChanged and set IsDirty to true when that is raised. Maybe also checking something significant happened.
Change it to false when the user saves.
If you somehow make or wrap your IsDirty as an IoBservable you can then just pass it in a factory method like ReactiveCommand.CreateFrom.... for a reactive command.
var command = ReactiveCommand.CreateFromTask(LogOnAsync, IsDirty);
You could separate stuff by putting say length in other observables. In which case you'd want to build a canexecute that observes multiple observables using WhenAnyValue.
https://www.reactiveui.net/docs/handbook/commands/
A common preference is to work with a property. You then use observable as property helper
The docs tell you to work this way.
https://www.reactiveui.net/docs/handbook/observable-as-property-helper/
https://www.reactiveui.net/docs/guidelines/framework/prefer-oaph-over-properties
public class RepositoryViewModel : ReactiveObject
{
public RepositoryViewModel()
{
canDoIt = this.WhenAny(x => x.StuffFetched, y => y.OtherStuffNotBusy, (x, y) => x && y)
.ToProperty(this, x => x.CanDoIt);
}
readonly ObservableAsPropertyHelper<bool> canDoIt;
public bool CanDoIt
{
get { return canDoIt.Value; }
}
}
If you think about it, CanDoIt above is fairly similar to what you'd probably want.
Because you'll also want to guard your commands using something like IsBusy so the user can't hit save ( or anything time consuming ) then immediately try to do something else like hit save again whilst it's still doing it's thing.
In my opinion, reactiveui is pretty clever stuff.
But.
You're paying a lot for that functionality in terms of a learning curve and arguably a counter intuitive way of doing things.
Related
Let's say I use objectify to load() an entity from datastore, then "modify" properties, then save() it back to datastore.
Let's assume no property has changed, e.g. a property has been "overwritten" with it's previous value.
Would objectify still execute the save() or is smart enough to realize there were no real changes and omit saving.
In other words: Does objectify assume there is a change only because I write a property, or will it actually look at the property to determine if there was a material change?
In short, your question is: Does Objectify provide dirty change detection?
No, it doesn't. At least not currently. This is mildly annoying sometimes, especially when you want to call several methods that may change an object - you don't want to execute multiple saves.
I've taken to writing code like this in my entities:
public void setFoo(final String value) {
if (!Objects.equals(this.foo, value)) {
this.foo = value;
ofy().defer().save().entity(this);
}
}
Which is a sort of poor-man's dirty change detection.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I have say the following View Model in my WPF application.
public class User : ViewModelBase
{
public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }
public int Age { get { return _age; } set { _age = value; OnPropertyChanged("Age"); } }
}
Now this information will be stored and pulled from a NoSQL database. My question is, should I keep separate Class in my project for the purpose of storage and retrieval to and from a NoSQL database and once the information is retrieved, build View Model or just using the View Model with NoSQL would be fine, surely that approach will save a lot of hassle.
What is the recommended way in NoSQL community in this regard ?
there are many different approaches to this, and it doesn’t really matter if you store the object in an RDBMS, NoSQL or some webservice which can again do what it wants.
it is true, that it’s easier if you don’t have to create a viewmodel - up to a certain point. Often you will find that extending the model by additonal properties which are only valid for your WPF implementation, and binding those properties, is easier than creating templates with different conditions. One example I have in mind would be for instance Color-Codes on your view, or if you have additional texts you want to display.
Those information can’t be in the original Model, because it isn’t relevant for anything else than your client. We’ve solved it in one project by annotating these properties with [XmlIgnore] - this way they weren’t serialized when talking to the server and we didn’t have to create an additional ViewModel. You might find that something like this is enough for you.
On the other hand for Web Applications, when serializing data with JSON it’s also important that you don’t want to send too much information to the client. Here it’s hard (sometimes not really possible) to adjust some autogenerated class definitions in order to annotate them appropriately. In thise case your only choice is to create special ViewModels and copy the data from one to the other.
In the end there comes one more factor - You might want to (or maybe rather, should) split your DataAccess logic from the rest. This way, if you decide to use a different storage mechanism you only need to reimplement that part, and make sure that your new Models can be transformed into the established ViewModels, so you don’t need to change everything.
You have to decide now for yourself - how fixed is your DataAccess infrastructure, will there ever change anything and are Annotations enough in order to hide additional information necessary for WPF bindings from your datastore? Or do you need a seperation between the Model and a ViewModel
I would like to trigger auto save on my model every time something changes, but only if the change came from the UI (i.e. the view). I mean, if the change came from the database, then there is no point in saving it again, it just came from the database...
However fetch and save can trigger change events (fetch because it brings potentially different state of the model, and save as it can bring the id for a newly created model)
So in the change event, I'd like to know what caused the change.
e.g. was it a call from the view?:
this.model.set("foo", "bar"); //triggers a change event as foo's value changed
Or a result of a sync operation?:
model.fetch(); //triggers a change event as the model changed in the DB
model.save(); //triggers a change event as the id was empty
Is there a way to tell them apart?
Once solution I thought of is wrapping view calls to the model's set with a setAttribute method, and triggering a custom changeDueToUIAction event, but I'm sure this has been solved before and I'm sure in a better way...
Or am I missing something altogether and the problem is that I ask the wrong question?
I'd say there are several custom solutions involving more or less boilerplate. And there is an easy one, though still adding a bit of boilerplate.
(Without any major change to Backbone) you can't know the source of the change (thinking about it, how would you have access to it in the Model#set method?). What you have access to in a listener is 2 objects. First one is the model which was changed. Second is the options you passed when calling the set method. So I guess you could do something like that:
// in the view
this.model.set('foo', 'bar', {'isFromUI': true});
// in your model
this.listenTo(this, 'change', function(model, flags) {
if(flags && flags.isFromUI) this.save();
});
I am wondering whether it is a good idea to make labels public so other classes can change them and get their value. Is this a good idea? If not, how should it be done then?
I wouldn't make the label public.
It would be better to add a public method that was specific to what the label was displaying, and have it update the label.
For example, if your label was a "System status" label, you might want to add (to your Form/UserControl):
public void SetStatusInformation(string currentStatus)
{
this.statusLabel.Text = currentStatus;
}
This allows you, later, to change how this information is displayed (in case you want to use a different control), and also simplifies your API, since the public methods are very clear to the user.
it's a bad idea. WinForms leaves many "what's the best way to do X?" questions open; and your best answer is to follow established patterns and practices (which aren't WinForms specific).
Read up on the MVP or MVC patterns. They are both high-level patterns which focus on seperating out your UI-specific code from your business-logic. Without this seperation your application can quickly become a maintenance nightmare, and things that should be simple get much more complicated.
For your specific scenario you would likely end up with a Model (your business-logic) which uses databinding to show it's data on the WinForms screen. When a change on the UI occurs it would be the Model that receives the change, and that change would propagate to the UI via databinding.
I would suggest wrapping in a setter property or method because it's very possible you'll have to do something like add logging or re-call on window's main thread if the caller is from another one. I found it easier to just always use code like the following when exposing functionality that lets clients update anything graphical.
public void SetStart()
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate()
{
this.SetStart();
});
}
else
{
progressBar1.Value = 0;
progressBar1.Visible = true;
}
}
Currently for ASP.Net stuff I use a request model where a context is created per request (Only when needed) and is disposed of at the end of that request. I've found this to be a good balance between not having to do the old Using per query model and not having a context around forever. Now the problem is that in WPF, I don't know of anything that could be used like the request model. Right now it looks like its to keep the same context forever (Which can be a nightmare) or go back to the annoying Using per query model that is a huge pain. I haven't seen a good answer on this yet.
My first thought was to have an Open and Close (Or whatever name) situation where the top level method being called (Say an event handling method like Something_Click) would "open" the context and "close" it at the end. Since I don't have anything on the UI project aware of the context (All queries are contained in methods on partial classes that "extend" the generated entity classes effectively creating a pseudo layer between the entities and the UI), this seems like it would make the entity layer dependent on the UI layer.
Really at a loss since I'm not hugely familiar with state programming.
Addition:
I've read up on using threads, but the
problem I have with a context just
sitting around is error and recovery.
Say I have a form that updates user
information and there's an error. The
user form will now display the changes
to the user object in the context
which is good since it makes a better
user experience not to have to retype
all the changes.
Now what if the user decides to go to
another form. Those changes are still
in the context. At this point I'm
stuck with either an incorrect User
object in the context or I have to get
the UI to tell the Context to reset
that user. I suppose that's not
horrible (A reload method on the user
class?) but I don't know if that
really solves the issue.
Have you thought about trying a unit of work? I had a similar issue where I essentially needed to be able to open and close a context without exposing my EF context. I think we're using different architectures (I'm using an IoC container and repository layer), so I have to cut up this code a bit to show it to you. I hope it helps.
First, when it comes to that "Something_Click" method, I'd have code that looked something like:
using (var unitOfWork = container.Resolve<IUnitOfWork>){
// do a bunch of stuff to multiple repositories,
// all which will share the same context from the unit of work
if (isError == false)
unitOfWork.Commit();
}
In each of my repositories, I'd have to check to see if I was in a unit of work. If I was, I'd use the unit of work's context. If not, I'd have to instantiate my own context. So in each repository, I'd have code that went something like:
if (UnitOfWork.Current != null)
{
return UnitOfWork.Current.ObjectContext;
}
else
{
return container.Resolve<Entities>();
}
So what about that UnitOfWork? Not much there. I had to cut out some comments and code, so don't take this class as working completely, but... here you go:
public class UnitOfWork : IUnitOfWork
{
private static LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot("UnitOfWork");
private Entities entities;
public UnitOfWork(Entities entities)
{
this.entities = entities;
Thread.SetData(slot, this);
}
public Entities ObjectContext
{
get
{
return this.Entities;
}
}
public static IUnitOfWork Current
{
get { return (UnitOfWork)Thread.GetData(slot); }
}
public void Commit()
{
this.Entities.SaveChanges();
}
public void Dispose()
{
entities.Dispose();
Thread.SetData(slot, null);
}
}
It might take some work to factor this into your solution, but this might be an option.