Skip to content

Commit

Permalink
Add content to ChangeNotification.aml
Browse files Browse the repository at this point in the history
References #11
  • Loading branch information
andreashuber-lawo committed Oct 27, 2015
1 parent 1596ea8 commit d433198
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,98 @@
xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
<introduction>
<para>
The <application>View</application> holds a copy of the data provided by the
<application>ViewModel</application>, which is why the <application>View</application> needs to be notified when
the data in the <application>ViewModel</application> changes. All <application>XAML</application>-based
<application>View</application> objects automatically look for implementations of
<codeEntityReference>T:System.Componentmodel.INotifyPropertyChanged</codeEntityReference> and
<codeEntityReference>T:System.Collections.Specialized.INotifyCollectionChanged</codeEntityReference>
and subscribe to the provided events as appropriate. <application>ViewModel</application> developers can reuse
the following implementations:
</para>
<list class="bullet">
<listItem>
<para>
<codeEntityReference>T:Lawo.ComponentModel.NotifyPropertyChanged</codeEntityReference>:
<application>ViewModel</application> implementations as well as the types of composite properties usually
derive from this base class.
</para>
</listItem>
<listItem>
<para>
Collection properties are usually of the type
<codeEntityReference>T:System.Collections.ObjectModel.ObservableCollection`1</codeEntityReference> or
<codeEntityReference>T:System.Collections.ObjectModel.ReadOnlyObservableCollection`1</codeEntityReference>.
</para>
</listItem>
</list>
<autoOutline/>
</introduction>
<section address="PrimitiveProperties">
<title>Primitive Properties</title>
<content>
<para>
A primitive property provides data that can directly be shown in the <application>View</application> (e.g.
<codeInline>string</codeInline>, <codeInline>double</codeInline>, <codeInline>int</codeInline>, etc.). A
property where the value may change while it is being displayed in the <application>View</application>
typically looks as follows:
</para>
<code source="..\Lawo.GlowAnalyzerProxy.Main\MainWindowViewModel.cs" region="ReadWriteProperty" language="c#"/>
<alert class="note">
<para>
<codeEntityReference linkText="SetValue">M:Lawo.ComponentModel.NotifyPropertyChanged.SetValue``1(``0@,``0,System.String)</codeEntityReference>
does its magic with the
<codeEntityReference>T:System.Runtime.CompilerServices.CallerMemberNameAttribute</codeEntityReference>.
<codeEntityReference linkText="SetValue">M:Lawo.ComponentModel.NotifyPropertyChanged.SetValue``1(``0@,``0,System.String)</codeEntityReference>
should therefore only ever be called directly from a setter of a property.
</para>
</alert>
<para>
Of course, properties that never change their value do not need to concern themselves with change
notification:
</para>
<code source="..\Lawo.GlowAnalyzerProxy.Main\MainWindowViewModel.cs" region="ReadOnlyProperty" language="c#"/>
</content>
</section>
<section address="CompositeProperties">
<title>Composite Properties</title>
<content>
<para>The getter of a composite property returns a value, which cannot directly be shown on the GUI:</para>
<code source="..\Lawo.GlowAnalyzerProxy.Main\MainWindowViewModel.cs" region="CompositeProperty" language="c#"/>
<para>
In this case the property value never changes. Of course, in general such properties can change their value
too. Then, change notification needs to be implemented by calling
<codeEntityReference linkText="SetValue">M:Lawo.ComponentModel.NotifyPropertyChanged.SetValue``1(``0@,``0,System.String)</codeEntityReference>
in the property setter just like a primitive property setter does.
</para>
<para>
Since the <application>View</application> will bind to properties of the returned value,
<codeInline>ConnectionViewModel</codeInline> must also implement
<codeEntityReference>T:System.Componentmodel.INotifyPropertyChanged</codeEntityReference>,
here again by deriving from
<codeEntityReference>T:Lawo.ComponentModel.NotifyPropertyChanged</codeEntityReference>.
</para>
</content>
</section>
<section address="CollectionProperties">
<title>Collection Properties</title>
<content>
<para>
Whenever a <application>View</application> needs to display multiple items in a list, the associated
<application>ViewModel</application> typically offers the necessary data through a property getter that
returns a collection implementing the
<codeEntityReference>T:System.Collections.Specialized.INotifyCollectionChanged</codeEntityReference>
interface:
</para>
<code source="..\Lawo.GlowAnalyzerProxy.Main\MainWindowViewModel.cs" region="CollectionProperty" language="c#"/>
<para>
The <application>.NET</application> framework implementations
<codeEntityReference>T:System.Collections.ObjectModel.ObservableCollection`1</codeEntityReference> and
<codeEntityReference>T:System.Collections.ObjectModel.ReadOnlyObservableCollection`1</codeEntityReference>
are almost always sufficient. The former should only be used if the <application>View</application> itself can
directly add and/or remove items. The latter is preferable when such operations are offered through
<application>ViewModel</application> methods and of course also when the collection is immutable from the
<application>View</application>.
</para>
</content>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,30 @@
<listItem>
<para>
<codeInline>CanEditSettings</codeInline>: Defines the value of the
<codeEntityReference>P:System.Windows.UIElement.IsEnabled</codeEntityReference>
<codeEntityReference linkText="IsEnabled">P:System.Windows.UIElement.IsEnabled</codeEntityReference>
property of the <codeEntityReference>T:System.Windows.Controls.TextBox</codeEntityReference> controls for
<ui>Listening Port</ui>, <ui>Provider Host Name</ui> and <ui>Provider Port</ui> as well as the
<ui>... </ui> <codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference>.
<ui>... </ui><codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference>.
</para>
</listItem>
<listItem>
<para>
<codeInline>CanStart</codeInline>: Defines the value of the
<codeEntityReference>P:System.Windows.UIElement.IsEnabled</codeEntityReference> property of the
<codeEntityReference linkText="IsEnabled">P:System.Windows.UIElement.IsEnabled</codeEntityReference> property of the
<ui>Start </ui><codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference>.
</para>
</listItem>
<listItem>
<para>
<codeInline>CanStop</codeInline>: Defines the value of the
<codeEntityReference>P:System.Windows.UIElement.IsEnabled</codeEntityReference> property of the
<codeEntityReference linkText="IsEnabled">P:System.Windows.UIElement.IsEnabled</codeEntityReference> property of the
<ui>Stop </ui><codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference>.
</para>
</listItem>
<listItem>
<para>
<codeInline>CanLoadFullEventDetail</codeInline>: Defines the value of the
<codeEntityReference>P:System.Windows.UIElement.Visibility</codeEntityReference> property of the
<codeEntityReference linkText="Visibility">P:System.Windows.UIElement.Visibility</codeEntityReference> property of the
<ui>Load Full Event </ui><codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference>.
</para>
</listItem>
Expand All @@ -77,15 +77,20 @@
<list class="bullet">
<listItem>
<para>
<codeInline>Start()</codeInline>: Is called when the <ui>Start</ui> button is clicked.
<codeInline>Start()</codeInline>: Is called when the <ui>Start </ui>
<codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference> is clicked.
</para>
</listItem>
<listItem>
<para><codeInline>Stop()</codeInline>: Is called when the <ui>Stop</ui> button is clicked.</para>
<para>
<codeInline>Stop()</codeInline>: Is called when the <ui>Stop </ui>
<codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference> is clicked.
</para>
</listItem>
<listItem>
<para>
<codeInline>LoadFullEventDetail()</codeInline>: Is called when the <ui>Load Full Event</ui> button is
<codeInline>LoadFullEventDetail()</codeInline>: Is called when the <ui>Load Full Event </ui>
<codeEntityReference>T:System.Windows.Controls.Button</codeEntityReference> is
clicked.
</para>
</listItem>
Expand Down
32 changes: 16 additions & 16 deletions Lawo.GlowAnalyzerProxy.Main/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ internal sealed class MainWindowViewModel : NotifyPropertyChanged, IDataErrorInf
private string logFolder;
private bool? autoScrollToMostRecentEvent;
private readonly CalculatedProperty<bool> canEditSettings;
//// [CalculatedProperty1]
#region CalculatedProperty1
private readonly CalculatedProperty<bool> canStart;
//// [CalculatedProperty1]
#endregion
private readonly CalculatedProperty<bool> canStop;
private Event selectedEvent;
private FlowDocument selectedEventDetail;
Expand All @@ -60,7 +60,7 @@ internal sealed class MainWindowViewModel : NotifyPropertyChanged, IDataErrorInf

[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called through reflection.")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Must be accessible from XAML.")]
//// [ReadOnlyProperty]
#region ReadOnlyProperty
public string Title
{
get
Expand All @@ -69,21 +69,21 @@ public string Title
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
//// [ReadOnlyProperty]
#endregion

public string ListeningPort
{
get { return this.listeningPort; }
set { this.SetValue(ref this.listeningPort, value); }
}

//// [ReadWriteProperty]
#region ReadWriteProperty
public string ProviderHostName
{
get { return this.providerHostName; }
set { this.SetValue(ref this.providerHostName, value); }
}
//// [ReadWriteProperty]
#endregion

public string ProviderPort
{
Expand All @@ -108,12 +108,12 @@ public bool CanEditSettings
get { return this.canEditSettings.Value; }
}

//// [CalculatedProperty3]
#region CalculatedProperty3
public bool CanStart
{
get { return this.canStart.Value; }
}
//// [CalculatedProperty3]
#endregion

public void Start()
{
Expand Down Expand Up @@ -142,24 +142,24 @@ public void SaveSettings()
this.settings.Save();
}

//// [CompositeProperty]
#region CompositeProperty
public ConnectionViewModel ConsumerConnection
{
get { return this.consumerConnection; }
}
//// [CompositeProperty]
#endregion

public ConnectionViewModel ProviderConnection
{
get { return this.providerConnection; }
}

//// [CollectionProperty]
#region CollectionProperty
public ReadOnlyObservableCollection<Event> Events
{
get { return this.readOnlyEvents; }
}
//// [CollectionProperty]
#endregion

public Event SelectedEvent
{
Expand Down Expand Up @@ -235,7 +235,7 @@ internal MainWindowViewModel(Settings settings)
this.providerConnection = new ConnectionViewModel(this);
this.readOnlyEvents = new ReadOnlyObservableCollection<Event>(this.events);

//// [TwoWayBinding]
#region TwoWayBinding
TwoWayBinding.Create(
this.settings.GetProperty(o => o.ListeningPort), this.GetProperty(o => o.ListeningPort));
TwoWayBinding.Create(
Expand All @@ -249,14 +249,14 @@ internal MainWindowViewModel(Settings settings)
a => a,
this.GetProperty(o => o.AutoScrollToMostRecentEvent),
a => a.GetValueOrDefault());
#endregion

//// [TwoWayBinding]
this.canEditSettings = CalculatedProperty.Create(
this.GetProperty(o => o.IsStarted),
this.GetProperty(o => o.IsStopped),
(isStarted, isStopped) => !isStarted && isStopped,
this.GetProperty(o => o.CanEditSettings));
//// [CalculatedProperty2]
#region CalculatedProperty2
this.canStart = CalculatedProperty.Create(
this.GetProperty(o => o.IsStarted),
this.GetProperty(o => o.IsStopped),
Expand All @@ -265,7 +265,7 @@ internal MainWindowViewModel(Settings settings)
this.GetProperty(o => o.LogFolder),
(isStarted, isStopped, lp, pp, lf) => !isStarted && isStopped && string.IsNullOrEmpty(ValidatePort(lp) + ValidatePort(pp) + ValidateFolder(lf)),
this.GetProperty(o => o.CanStart));
//// [CalculatedProperty2]
#endregion
this.canStop = CalculatedProperty.Create(
this.GetProperty(o => o.IsStopped), s => !s, this.GetProperty(o => o.CanStop));

Expand Down

0 comments on commit d433198

Please sign in to comment.