In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.
Related
Sometimes when i wrote i had to eg edit a text in TextBlock which is on other Page, then I did this trick:
private static MainPage _gui;
public static void SetTitleText(string text) => _gui.TitleText.Text = text;
public static Visibility InfoCenterStackPanelVisibility
{
get { return _gui.InfoCenterStackPanel.Visibility; }
set { _gui.InfoCenterStackPanel.Visibility = value; }
}
public MainPage()
{
InitializeComponent();
_gui = this;
}
And in other page i just call MainPage.SetTitleText etc;
And I want to know, is any other, better way to acces these items, without creating _gui?
ps I looked for any likely looking topics, I did not found an answer
Generally this is a bad idea because if your app gets complex enough you will end up in a situation where your MainPage doesn't exist at runtime, and thus will crash when you try and access the (null) static instance. This could happen eg if you implement Suspend / Terminate / Resume in a multi-page app, or you implement a contract like Share. Even if your current project is simple, this is a bad habit to get into if you build larger apps in the future.
Typically you would use an MVVM approach to have this information in your data model, and then the MainPage would just bind to the data model (or explicitly read values out of it). There are a lot of web resources for MVVM - just use your favourite search engine.
I recently made a very simple app in WPF that simply reads data from a few TextBoxes and updates records in an SQL Server database. I also put back and forward buttons to allow the user to scroll through the available records. Everytime the user clicks Next on the app, the UI gets updated with the values from the new record through a method I called updateControls(), which looks like this:
private void updateControls()
{
IQueryable<Comment> query = from t in container.Comment
where t.Id == browseIndex
select t;
if (query.Count<Comment>() > 0)
{
currentComment = query.First<Comment>();
txtID.Text = currentThought.Id.ToString();
txtComment.Text = currentComment.thought;
txtDate.DisplayDate = currentComment.date;
txtDate.Text = currentComment.date.ToString();
}
}
This is simple, and it works like a charm. But I recently discovered the world of data-binding, where you can supposedly eliminate all this boilerplate code of manually updating controls and have them update themselves whenever the model changes.
After much experimentation and reading through various tutorials, I find that, for this to work, my data object must implement the INotifyPropertyChanged interface, which means need to use explicit setters on the properties I wish to update on my UI, like this:
public class Comment: INotifyPropertyChanged {
private string comment;
public event PropertyChangedEventHandler PropertyChanged;
public string Comment { get { return this.comment;}
set {
this.comment = value;
NotifyPropertyChanged("Comment");
}
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null ) this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
This is a lot more code than simply manually updating my UI with the data I want. Also, since this class is part of an Entity Model, the INotifyPropertyChanged interface has to be implemented in a class apart from the model classes, since model classes get regenerated when the model is updated. Which leads me to my question: why ever would I want to use data-binding in a real world application when it is much simpler to simply update my UI manually? Or is there an alternative way to do this that I'm not seeing?
The MVVM pattern dissociates the GUI logic from the core logic.
You can have the same model for several totally different controls and on the other way have one complex control leverage on several totally different models (the ViewModel is just the glue).
If you work on a team, you may have one guy working on the GUI part and another one dedicated to databases.
The database (model) is no more enslaved by the way you show the data, as long as the ViewModel notifies its changes, it'll be up to the View to decide to catch it or not (with a simple binding)
when you work with datatemplate, everything will make a lot more sense because it'll be VERY easy to render complex
There are many reasons why this pattern is great, there are plenty of articles on internet
First I'm not mad, because I use MVVM in WinForms-) I know about MVP (Model View Presenter) pattern and its variants. When I started this project I was going to learn WPF and use it, but I'm forced to rush program development, and have no time to learn WPF, so I have to write it in WinForms which I know well.
So in short I have a large data oriented smart client application, which is close to finish, I have all Models and ViewModels done (Infrastructure, Domain, Presentation done) UI is done too, now I only need to wire UI to ViewModels.
First I started wiring it using the standard winforms way (BindingSources, and simple databinding) but when I did 30-50% of binding I found out that my program works very slow, I have like 100-150 bound properties total so far, 30 of them are domain root entity (aggregate root) bindings to its EditForm. So databinding doesn't work well in this situation, lots of unnecessary updates, cascade updates of entire view when something small changes, unclear behavior, and other ugly stuff. It smells like very unreliable code, on which I have little control.
So I began to rewrite wiring as pure clean WinForms code (subscribing to PropertyChange and ListChanged events, and setting ViewModels property on my own from UI). Lot's of code to write but it works much faster, I have full control on this, and it feels much more reliable.
So what's your thoughts on this guys?
Anyone had such experience? What's your verdict on "To DataBind or Not"?
You might want to take a look at Truss. It provides a WPF-style binding manager that works on POCOs. It makes using MVVM with Windows Forms much more effective.
Using data-binding in WinForms is really painful, and subscribing to INotifyPropertyChanged events and doing things manually is overkill. I really like MVVM even on WinForms for it's great testability and maintainability but not at a price of 3X times more code to write. So for new code I use now combined View+ViewModel.
Another possibility is to use a inherited BindingSource component for data-binding in WinForms.
For example: http://ingebrigtsen.info/2010/08/31/mvvm-in-windows-forms/.
It works smoothly even in NET CF Environments.
I have modified the implementation to achieve two goals:
an easy databinding support for my ViewModels through WinForms designer
multithreading support with control.Invoke because the default BindingSource doesn't support it. Now it reacts to PropertyChanged events from a background thread.
Here is my simple ViewModelBindingSource class:
public class ViewModelBindingSource : BindingSource
{
private readonly Control _control = new Control();
private object _viewModel;
private Type _viewModelType;
public ViewModelBindingSource()
{
}
public ViewModelBindingSource(IContainer container)
: base(container)
{
}
public ViewModelBindingSource(object dataSource, string dataMember)
: base(dataSource, dataMember)
{
}
public object ViewModel
{
get { return _viewModel; }
set { _viewModel = value; }
}
public Type ViewModelType
{
get { return _viewModelType; }
set
{
if (value != null)
{
// save the type of our viewmodel
_viewModelType = value;
// create an instance of our viewmodel - so we don't need codebehind
_viewModel = Activator.CreateInstance(_viewModelType);
// add the viewmodel instance to the internal IList collection of the bindingsource
Add(_viewModel);
// move to the first element
MoveFirst();
// set the datasource of the binding source to the first element
// this is necessary for data binding of all windows forms controls
DataSource = this[0];
}
}
}
/// <summary>
/// Pass the call to the main thread for windows forms
/// This is needed for multithreading support.
/// </summary>
/// <param name="e"></param>
protected override void OnListChanged(ListChangedEventArgs e)
{
if (_control != null && _control.InvokeRequired)
_control.Invoke(new Action<ListChangedEventArgs>(OnListChanged), e);
else
{
base.OnListChanged(e);
}
}
Looking for guidance on where to place code which is dependent upon changes to a property.
For example, I have a view model which is used to hold state for an applications settings
public SettingsViewModel(ISettingsRepository settings)
{
_settings = settings;
// ...
}
For each change to a settings property we have to persist this change to the repository, and on some properties, other properties are affected, so additional code is required.
I started off just adding this logic to the setter
public ProjectCollection Projects
{
get { return _projects; }
set
{
if (_projects == value) return;
_projects = value;
RaisePropertyChanged("Projects");
// Extra work needed when collection of projects change
_settings.SaveProjects(_projects);
Startable = _projects != null && _projects.Count > 0;
}
}
But then swapped over to wiring up the PropertyChanged event for INotifyPropertyChanged and removed the additional code out of the property setter
public SettingsViewModel(ISettingsRepository settings)
{
_settings = settings;
// ...
PropertyChanged += onPropertyChanged;
}
void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Projects":
_settings.SaveProjects(Projects);
Startable = Projects != null && Projects.Count > 0;
break;
// ...
}
}
public ProjectCollection Projects
{
get { return _projects; }
set
{
if (_projects == value) return;
_projects = value;
RaisePropertyChanged("Projects");
}
}
Having the logic inside the setter means less code to write, less chance of making a mistake wiring up the wrong property name (unit test should pick this up though) and would be slightly faster, although probably insignificant.
Having the logic wired up to an event seems to be a more maintainable approach, so long as the methods are appropriately named it should be easier to follow the code, and means the setter isn't doing other work besides setting the property. I'm guessing it might also provide more flexibility, using the example above, if the requirements changed so that persisting of changes happened from another event e.g. "Save" button click instead property change, then the code should be easier to change.
I appreciate this is a subjective question, but I'm new to the MVVM pattern (although I guess it may hold true for any setter logic?) so am looking for other reasons before I settle on an approach. Thanks!
When deciding what code to put where, remember this: a ViewModel is for presenting the data to the View. It can massage or manipulate the data a little to do so (within reason of course - changing a value to a color could be considered absolutely fine to do). The ViewModel doesn't know anything about the UI, and it doesn't know anything about saving data.
The property setters should be kept as simple as possible, and they should notify if anything relies on them (which mostly will be the case - the VM is used for binding). This means that your second example utilizing the OnPropertyChanged() event handler is a far better option than the first example.
However, it still knows too much for my liking. I would raise events which the Model can subscribe to, and let the Model do the work. The ViewModel should just say "hey, my data has changed, I don't care what you do about it but i've told you so do whatever you like". The Model can then either save instantly, or what till more changes have taken place before persisting the data.
What's the best way (in a WPF app, C#) of implementing control behaviour that is based around the current status/mode for the window?
For example let's say the modes might be simply OFFLINE, ONLINE for example. So when OFFLINE you want the configuration entry controls to be active, however as soon as processing starts (ONLINE) then you want these controls to be grey'ed out.
Any suggestions re pattern/approach to manage this? I'm wondering if there is a publish/subscribe approach that would be best, or just create a helper method like "SetStatus" and make all the calls to controls from here.
thanks
I would bind the IsEnabled property of whatever contains your configuration entry controls to a boolean value that inspects the current status/mode.
The downside to this approach is that you will have to make a call to this property every time the Mode is changed. But this can be made easier by using properties that wrap around a member variable
//Assumes your mode enum is defined and named WindowModes
private WindowModes m_CurrentMode;
public WindowModes
{
get { return m_CurrentMode; }
set
{
m_CurrentMode = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CanConfigure"));
}
}
public bool CanConfigure
{
return(WindowMode == WindowModes.Online)
}
Of course if your Mode IS boolean such as ONLINE/OFFLINE. then you could simply wrap that value the same way.
This approach of course has various scalability issues and is quite class restrictive, but I've found it useful in some scenarios.