How to wait for WPF Binding Delay to complete - c#

My ViewModel implements the INotifyPropertyChanged and INotifyDataErrorInfo interfaces. When the property is changed, the validation triggers, which in turn enables\disable the Save button.
Because the Validation step is time consuming I've made use of the Delay binding property.
My problem is that I can type my changes and press Save before the 'Name' property is updated.
I'd like to force an immediate update on the TextBox.Text when I press SaveChanges. At the moment, I have to add a sleep before executing to ensure all changes have occurred on the ViewModel.
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, Delay=1000}" />
<Button Command="{Binding SaveChanges}" />
Does anyone have some pointers?

Since .NET 4.5 there exists BindingOperations
BindingOperations.GetSourceUpdatingBindings(this).ToList().ForEach(x => x.UpdateSource());

You can implement the IPropertyChanged interface on your viewModel, and then from your Name property setter to check if the value has changed, and raise an OnPropertyChanged event for that property.
You can use that property changed event to wire up your SaveChanges command CanExecute method to return false if not updated yet, and return true if the delay is elapsed and the property is updated.
Therefore, the SaveChanges button stays disabled until the CanExecute returns true.

Not sure the purpose of having a delay in your case. However, couple of other options that I can think of are below.
Set UpdateSourceTrigger to explicit and handle the delay in your own way. Then you can UpdateSource when ever you want.
Use Binding.IsAsync which will get and set values asynchronously.
Here is a good example.

Create a Custom Control Text Box and set delay time Property.
public class DelayedBindingTextBox : TextBox {
private Timer timer;
private delegate void Method();
/// <summary>
/// Gets and Sets the amount of time to wait after the text has changed before updating the binding
/// </summary>
public int DelayTime {
get { return (int)GetValue(DelayTimeProperty); }
set { SetValue(DelayTimeProperty, value); }
}
// Using a DependencyProperty as the backing store for DelayTime. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DelayTimeProperty =
DependencyProperty.Register("DelayTime", typeof(int), typeof(DelayedBindingTextBox), new UIPropertyMetadata(667));
//override this to update the source if we get an enter or return
protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e) {
//we dont update the source if we accept enter
if (this.AcceptsReturn == true) { }
//update the binding if enter or return is pressed
else if (e.Key == Key.Return || e.Key == Key.Enter) {
//get the binding
BindingExpression bindingExpression = this.GetBindingExpression(TextBox.TextProperty);
//if the binding is valid update it
if (BindingCanProceed(bindingExpression)){
//update the source
bindingExpression.UpdateSource();
}
}
base.OnKeyDown(e);
}
protected override void OnTextChanged(TextChangedEventArgs e) {
//get the binding
BindingExpression bindingExpression = this.GetBindingExpression(TextBox.TextProperty);
if (BindingCanProceed(bindingExpression)) {
//get rid of the timer if it exists
if (timer != null) {
//dispose of the timer so that it wont get called again
timer.Dispose();
}
//recreate the timer everytime the text changes
timer = new Timer(new TimerCallback((o) => {
//create a delegate method to do the binding update on the main thread
Method x = (Method)delegate {
//update the binding
bindingExpression.UpdateSource();
};
//need to check if the binding is still valid, as this is a threaded timer the text box may have been unloaded etc.
if (BindingCanProceed(bindingExpression)) {
//invoke the delegate to update the binding source on the main (ui) thread
Dispatcher.Invoke(x, new object[] { });
}
//dispose of the timer so that it wont get called again
timer.Dispose();
}), null, this.DelayTime, Timeout.Infinite);
}
base.OnTextChanged(e);
}
//makes sure a binding can proceed
private bool BindingCanProceed(BindingExpression bindingExpression) {
Boolean canProceed = false;
//cant update if there is no BindingExpression
if (bindingExpression == null) { }
//cant update if we have no data item
else if (bindingExpression.DataItem == null) { }
//cant update if the binding is not active
else if (bindingExpression.Status != BindingStatus.Active) { }
//cant update if the parent binding is null
else if (bindingExpression.ParentBinding == null) { }
//dont need to update if the UpdateSourceTrigger is set to update every time the property changes
else if (bindingExpression.ParentBinding.UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged) { }
//we can proceed
else {
canProceed = true;
}
return canProceed;
}
}

I had the same issue in a WPF application and came up with the following solution:
public class DelayedProperty<T> : INotifyPropertyChanged
{
#region Fields
private T actualValue;
private DispatcherTimer timer;
private T value;
#endregion
#region Properties
public T ActualValue => this.actualValue;
public int Delay { get; set; } = 800;
public bool IsPendingChanges => this.timer?.IsEnabled == true;
public T Value
{
get
{
return this.value;
}
set
{
if (this.Delay > 0)
{
this.value = value;
if (timer == null)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(this.Delay);
timer.Tick += ValueChangedTimer_Tick;
}
if (timer.IsEnabled)
{
timer.Stop();
}
timer.Start();
this.RaisePropertyChanged(nameof(IsPendingChanges));
}
else
{
this.value = value;
this.SetField(ref this.actualValue, value);
}
}
}
#endregion
#region Event Handlers
private void ValueChangedTimer_Tick(object sender, EventArgs e)
{
this.FlushValue();
}
#endregion
#region Public Methods
/// <summary>
/// Force any pending changes to be written out.
/// </summary>
public void FlushValue()
{
if (this.IsPendingChanges)
{
this.timer.Stop();
this.SetField(ref this.actualValue, this.value, nameof(ActualValue));
this.RaisePropertyChanged(nameof(IsPendingChanges));
}
}
/// <summary>
/// Ignore the delay and immediately set the value.
/// </summary>
/// <param name="value">The value to set.</param>
public void SetImmediateValue(T value)
{
this.SetField(ref this.actualValue, value, nameof(ActualValue));
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetField<U>(ref U field, U valueField, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<U>.Default.Equals(field, valueField)) { return false; }
field = valueField;
this.RaisePropertyChanged(propertyName);
return true;
}
protected void RaisePropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
To use this then you would need to create a property like:
public DelayedProperty<string> Name { get;set; } // Your choice of DP or INPC if you desire.
And change your TextBox to:
<TextBox Text="{Binding Name.Value, UpdateSourceTrigger=PropertyChanged}" />
Then when processing the SaveChanges Command you can call:
this.Name?.FlushValue();
You will then be able to access the ActualValue from the property. I currently subscribe to the PropertyChanged event on the Name property but I am considering making a specific event for this.
I was hoping to find a solution that would be simpler to use but this is the best I could come up with for now.

Related

How can I properly reset a value associated with a ComboBox, from within a PropertyChanged event?

I have a ComboBox that is bound to a property on my ViewModel (from hear on "VM".) When a user makes a selection on the ComboBox it properly updates the bound property in my VM. Within my UI code, I have subscribed to the PropertyChanged event on my VM.
As it should behave, when the user makes a selection within the ComboBox, my PropertyChanged event is correctly executing in my UI back-end code. When the UI code catches the change of this property, under certain selection conditions I need to halt the process and request the user for additional information. From the UI, I send them a dialog. If they cancel the dialog, I reset the value in the VM that is associated with the ComboBox controls SelectedValue.
This is what I've observed. When the operation is cancelled by the user, my VM property is being set to the new value. However, the ComboBox is still showing the text value of the original entry that has now changed. How can I force the ComboBox to update itself from within my PropertyChanged event? In this case, I think it's just a textual issue or numeric index change that's referencing the text data from the bound collection. The data is correct in the VM but the display value for the ComboBox is wrong.
EXAMPLE
ComboBox Details
<ComboBox
ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
SelectedValue="{Binding MySelectionIsAnEnumeration}"
DisplayMemberPath="Text"
SelectedValuePath="EnumerationValue"
Height="27" />
Sorry for the wordy properties on the VM, but that's to explain what's happening. My ListOfComboBoxDisplayObjects collection represents a set of enumerator values that are stored in the path within SelectedValuePath. The descriptive text for each value is pulled from the ListOfComboBoxDisplayObjects which is a special list strictly created for the UI. This basically pairs an enumeration value with a meaningful description.
ListOfComboBoxDisplayObjects Definition (from within VM)
Edit #1 - Added this definition to my example
private ObservableCollection<BindableEnumerationItem<Values>> _listOfComboBoxDisplayObjects;
public ObservableCollection<BindableEnumerationItem<Values>> ListOfComboBoxDisplayObjects
{
get { return _listOfComboBoxDisplayObjects; }
private set
{
if (value != _listOfComboBoxDisplayObjects)
{
_listOfComboBoxDisplayObjects= value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ListOfComboBoxDisplayObjects)));
}
}
}
MySelectionIsAnEnumeration Definition (From within VM)
*Edit #1: Adding this code definition.
private Values_mySelectionIsAnEnumeration ;
public Values MySelectionIsAnEnumeration
{
get { return _mySelectionIsAnEnumeration; }
set
{
//Double-checked this-- value is different on the second-call to change this value, once the UI cancels the operation.
if (value != _mySelectionIsAnEnumeration)
{
_mySelectionIsAnEnumeration= value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MySelectionIsAnEnumeration )));
}
}
}
Pertinent Values Associated with ListOfComboBoxDisplayObjects
These values are generated in the ctor of the VM. They are fixed throughout the application.
Item #1
Text: "This is a Foo!"
Value: Values.Foo
Item #2:
Text: "Hi, I'm Bar."
Value: Values.Bar
Item #3:
Text: "This is Baz. I need to ask a question before I can be used."
Value: Values.Baz
PropertyChanged Event - From the UI Back-End
private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "MySelectionIsAnEnumeration":
if (VM.MySelectionIsAnEnumeration == Values.Baz)
{
//Prompt the user and get DialogResult.
bool answerGiven = AskAQuestionAndGetAResult();
if(!answerGiven)
VM.MySelectionIsAnEnumeration = Values.Foo;
}
break;
}
}
After executing the above code, what I'm observing is that the VM.MySelectionIsAnEnumeration value is indeed changing to the proper value of Value.Foo when a user cancels the operation within AskAQuestionAndGetAResult(). However, after it's finished the ComboBox still reads "This is Baz. I need to ask a question before I can be used.", which is obviously the display value associated with Value.Baz.
How can I update both the underlying VM property AND the display text on the CombobBox to correctly show the valued that is now stored in VM.MySelectionIsAnEnumeration?
Edit #2
Below is the code efor my BindableEnumerationItem that I use within my Observable Collections for comboxes and list boxes. This is used throughout my application in simpler cases and has caused no issue. Please note, this is my actual, unaltered code. I've not renamed anything. My comboboxes can bind to each Item property for a type-safe property and DisplayText is the descriptor text.
public class BindableEnumerationItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private T _item;
public BindableEnumerationItem(T item, string displayText)
{
_item = item;
_displayText = displayText;
}
private string _displayText;
public string DisplayText
{
get { return _displayText; }
set
{
if (value != _displayText)
{
_displayText = value;
PropertyChanged(this, new PropertyChangedEventArgs("DisplayText"));
}
}
}
public T Item
{
get { return _item; }
set
{
_item = value;
PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
}
create an extension that will wire up the command from your viewmodel in xaml to the selector, which in this case is the combobox.
public partial class Extensions
{
public static readonly DependencyProperty SelectionChangedCommandProperty = DependencyProperty.RegisterAttached("SelectionChangedCommand", typeof(ICommand), typeof(Extensions), new UIPropertyMetadata((s, e) =>
{
var element = s as Selector;
if (element != null)
{
element.SelectionChanged -= OnSelectionChanged;
if (e.NewValue != null)
{
element.SelectionChanged += OnSelectionChanged;
}
}
}));
public static ICommand GetSelectionChangedCommand(UIElement element)
{
return (ICommand)element.GetValue(SelectionChangedCommandProperty);
}
public static void SetSelectionChangedCommand(UIElement element, ICommand value)
{
element.SetValue(SelectionChangedCommandProperty, value);
}
private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var element = sender as Selector;
var command = element.GetValue(SelectionChangedCommandProperty) as ICommand;
if (command != null && command.CanExecute(element.SelectedItem))
{
command.Execute(element.SelectedItem);
e.Handled = true;
}
}
}
Create the command in the viewmodel that handles the value changed event.
public ICommand EnumerationValueChangedCommand
{
get
{
return new Command(
() =>
{
if (VM.MySelectionIsAnEnumeration == Values.Baz)
{
//Prompt the user and get DialogResult.
bool answerGiven = AskAQuestionAndGetAResult();
if (!answerGiven)
VM.MySelectionIsAnEnumeration = Values.Foo;
}
});
}
}
And then bind using that extension. ext is the namespace for your extensions.
<ComboBox
ItemsSource="{Binding ListOfComboBoxDisplayObjects}"
SelectedValue="{Binding MySelectionIsAnEnumeration}"
DisplayMemberPath="Text"
SelectedValuePath="EnumerationValue"
ext:Extensions.SelectionChangedCommand="{Binding EnumerationValueChangedCommand}"
Height="27" />

Update View when property value changed inside setter

I have checkbox in my view which has bound to the property in the viewmodel. When I check/uncheck the checkbox, there is one condition in setter of the property which updates the same property if the condition is true. But when the property gets updated corresponding view does not change.
Here is the code:
View:
<CheckBox IsChecked="{Binding HoldingPen,Mode="Twoway" ,UpdateSourceTrigger=PropertyChanged}"/>
ViewModel:
public bool HoldingPen
{
get{m_holdingPen;}
set
{
m_hodingPen=value;
onPropertyChanged("HoldingPen");
OnHoldingPenCheckChanged();
}
public void OnHoldingPenCheckChanged()
{
if(HoldingPen && some other condition)
{
HoldingPen=false; //Here view should be updated simultaneously
}
}
I think it's a result of having two onPropertyChanged events fire, once with a value of true and one with a value of false
Typically for this kind of logic I prefer to use the PropertyChanged event instead of hiding the logic in property setters.
public class MyClass()
{
public MyClass()
{
// attach property changed in constructor
this.PropertyChanged += MyClass_PropertyChanged;
}
private void MyClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "HoldingPen")
OnHoldingPenCheckChanged();
}
public bool HoldingPen
{
get{ m_holdingPen; }
set
{
if (m_hodingPen == value)
return;
m_hodingPen=value;
onPropertyChanged("HoldingPen");
}
}
public void OnHoldingPenCheckChanged()
{
if(HoldingPen && some other condition)
{
HoldingPen=false; //Here view should be updated simultaneously
}
}
}
This has the additional benefit of having any custom code to modify a value in one location, rather than going through each setter when looking for something.

c# DataChanged event does trigger on a windows form (Desktop Application)

I have a form, I select some checkboxes, edit some text field, select from a combobox etc. then I click Exit. Based on the fact that "Data has been changed ??" I wish to perform actions. The problem is I can't get the event work :
private void DataChanged(object sender, EventArgs e)
{
MessageBox.Show("Data is changed", "debug");
isDataSaved = false;
}
When is this method called, how do I make it work? Is this supposed to get fired when the form's fields have some data i.e filL a text box ?
I dont really get the API: DataChanged event
Note: I'm following Mike Murach C# 5th edition chapter 10 example.
Edit (exact words from book):
Generate an event handler named DataChanged for the
SelectedIndexChanged event of the XXXX Name combo box. Then , wire
this event handler to the TextChanged event of the YYYYY Method label
and add the code to this event handler so it sets the isDataSaved
variable to false
When I double click on the commbo box the generated event handler it is not named DataChanged but cboNames_SelectedIndexChanged... (is this a book screw up or me total noob ? PS: There is no .. 'database' in the project)
Personally I mostly use databinding these days to get notified of changes in data.
A data holder class, which implements INotifyPropertyChanged. This interface gives you the possibility to get notified when the value of a property changes.
public class SomeData: INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string name = "") {
if (!EqualityComparer<T>.Default.Equals(field, value)) {
field = value;
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(name));
}
}
}
private boolean _someBoolean;
public int SomeBoolean {
get { return _someBoolean; }
set {
SetProperty(ref _someBoolean, value);
}
}
private string _someString;
public string SomeString {
get { return _someString; }
set {
SetProperty(ref _someString, value);
}
}
// etc
}
Now our form, which uses the data class and it's INotifyPropertyChanged implementation to get notified when a change in data occurs.
public partial class SomeForm: Form {
private SomeData _data;
private void LoadData() {
_data = new SomeData();
_data.PropertyChanged += Data_PropertyChanged;
}
private void SaveData() {
// TODO: Save data
}
private void AddDataBindings() {
checkbox1.DataBindings.Add("Checked", _data, "SomeBoolean");
textbox1.DataBindings.Add("Text", _data, "SomeString");
// add other
}
private void Data_PropertyChanged(object sender, PropertyChangedEventArgs e) {
// Here you can add actions that must be triggered when some data changes.
if (e.PropertyName == "SomeBoolean") {
// Do something when some-boolean property changes
}
// Set is-changed-boolean to true to 'remember' that something has changed.
_isChanged = true;
// Give message
MessageBox.Show(string.Format("Data changed, property {0}", e.PropertyName));
}
private bool _isChanged = false;
protected void Form_Closed(object sender, EventArgs e) {
// If data is changed, save it
if (_isChanged) {
SaveData();
}
}
}
Your problem is not known where the method DataChanged use and how. I have a suggestion for you that is use Focus Activated in properties.Add datachanged printing method Activated
good luck.
You must make properties this like

How to use INotifyPropertyChanged on a property in a class within a class..?

My issue seems to be "scope", though I'm not certain that's the right terminology. I want to notify a read-only list to re-evaluate itself when a property within a custom object is set. I believe it is simply not aware of it's existence. Maybe there is an easy way around this I cannot think of, but I'm drawing a blank.
I find this hard to put into words, so here's simplified code with my comments on what I expect to happen.
Properties within object in which I am databinding to:
private CvarAspectRatios _aspectRatio = new CvarAspectRatios("none", GetRatio());
public CvarAspectRatios AspectRatio
{
get { return _aspectRatio; }
set
{ // This setter never gets hit since I bind to this
if (value != null) // object's 'Value' property now.
{
_aspectRatio = value;
NotifyPropertyChanged("AspectRatio");
NotifyPropertyChanged("ResolutionList"); // I want to inform ResolutionList
} // that it needs to repopulate based
} // on this property: AspectRatio
}
private ResolutionCollection _resolutionList = ResolutionCollection.GetResolutionCollection();
public ResolutionCollection ResolutionList
{
get
{
ResolutionCollection list = new ResolutionCollection();
if (AspectRatio != null && AspectRatio.Value != null)
{
foreach (Resolutions res in _resolutionList.Where(i => i.Compatibility == AspectRatio.Value.Compatibility))
{
list.Add(res);
}
return list;
}
return _resolutionList;
}
}
CvarAspectRatios Class:
public class CVarAspectRatios : INotifyPropertyChanged
{
private string _defaultValue;
public string DefaultValue
{
get { return _defaultValue; }
set { _defaultValue = value; NotifyPropertyChanged("DefaultValue"); }
}
private AspectRatios _value;
public AspectRatios Value
{
get { return _value; }
set
{
_value = value;
NotifyPropertyChanged("Value");
NotifyPropertyChanged("ResolutionList"); // This value gets set, and I'd like for ResolutionList to update
} // but it cannot find ResolutionList. No errors or anything. Just
} // no update.
public AspectRatios() { }
public AspectRatios(string defaultValue, AspectRatios val)
{
DefaultValue = defaultValue;
Value = val;
}
// Implementation of INotifyPropertyChanged snipped out here
}
What do you folks think? If you'd like a sample application I can whip one up.
Since CVarAspectRatios implements INotifyPropertyChanged, you can have the viewmodel class subscribe to the PropertyChanged event for the AspectRatio.
public class YourViewModel
{
public YourViewModel()
{
AspectRatio.PropertyChanged += AspectRatio_PropertyChanged;
}
void AspectRatio_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
NotifyPropertyChanged("ResolutionList");
}
}
Just bear in mind that if you discard that AspectRatio object (if the object reference changes and not just the value property of that object), you should unsubscribe from the event on the discarded one.
To just transform your existing code into something which should work:
private CvarAspectRatios _aspectRatio; //No field initialization because that would not attach event handler, you could do it though and take care of the handler alone in the ctor
public CvarAspectRatios AspectRatio
{
get { return _aspectRatio; }
set
{
if (_aspectRatio != value) // WTH # "value != null"
{
_aspectRatio.PropertyChanged -= AspectRatio_PropertyChanged;
_aspectRatio = value;
_aspectRatio.PropertyChanged += new PropertyChangedEventHandler(AspectRatio_PropertyChanged);
NotifyPropertyChanged("AspectRatio");
}
}
}
void AspectRatio_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
NotifyPropertyChanged("ResolutionList");
}
}
Why don't you factor out re-populating ResolutionList into a separate private method which gets called from the setter of AspectRatios?
If a list needs to update based on a changed property, the list (or a list manager object, for better encapsulation) would normally need to subscribe to the PropertyChanged event of the object hosting the property. If the list is itself a property of the same object, as in this case, it would be simpler and leaner for the property's setter to call a method that updates the list.

C# Variable labels?

Say I have a box that says ENABLED or DISABLED.
How can I make the text vary depending on a state?
public void CheckBox1CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked) {
checkBox1.Text = "Enabled";
}
else {
checkBox1.Text = "Disabled";
}
}
box.Text = (box.Enabled ? "ENABLED" : "DISABLED");
If I understand correctly, you are asking how to have a label or some other bit of UI text automatically update to reflect a "state variable". This is just one way to accomplish what you're describing:
I would do it by having a central state object which implements INotifyPropertyChanging and INotifyPropertyChanged. When your application initializes, attach event handlers to the events those interfaces expose, and one of those event handlers can change the text of the label when property (Foo) changes.
public class State : INotifyPropertyChanging, INotifyPropertyChanged
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanging(PropertyChangingEventArgs e)
{
if (this.PropertyChanging != null)
{
this.PropertyChanging(this, e);
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, e);
}
}
public bool Foo
{
get
{
return foo;
}
set
{
if (value != foo)
{
this.OnPropertyChanging(new PropertyChangingEventArgs("Foo"));
foo = value;
this.OnPropertyChanged(new PropertyChangedEventArgs("Foo"));
}
}
}
private bool foo = false;
}
protected void HandleStateChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Foo")
{
box.Text = state.Foo ? "Enabled" : "Disabled";
}
}
What jeffamaphone said, but I should add that any time that state changes you will have to make sure to run that same code. The easiest way to insure this happens is by binding the box.Text property to the state object that you are interested in. That way, any change made to the object is immediately reflected in the text.
This blog post
helped me get started with data binding.... because I love FAQs.
The last few months I have been going with a slightly lighter weight solution than implementing a whole class to manage state. I usually define an enum which indicates the types of states available in the UI, then I have a function that makes changes to the UI, based on the state selected. This approach has been very successful, and not too heavy in terms of the amount of code needed to be written.
If I want to know what states are available in the UI, I can check the values of the enum.
public enum SystemState
{
/// <summary>
/// System is under the control of a remote logging application.
/// </summary>
RemoteMode,
/// <summary>
/// System is not under the control of a remote logging application.
/// </summary>
LocalMode
}
public interface IView
{
void SetState(SystemState state);
}
//method on the UI to modify UI
private void SetState(SystemState state)
{
switch (state)
{
case SystemState.LocalMode:
//for now, just unlock the ui
break;
case SystemState.RemoteMode:
//for now, just lock the ui
break;
default:
throw new Exception("Unknown State requested:" + state);
}
}
//now when you change state, you can take advantage of intellisense and compile time checking:
public void Connect()
{
SetState(SystemState.RemoteMode);
}

Categories

Resources