示例#1
0
        /// <summary>
        /// Renders the view based on the provided view model.
        /// </summary>
        /// <param name="viewModel">
        /// The view model which must be reflected by the view.
        /// </param>
        private void Render(StampCollectionViewModel viewModel)
        {
            /* In this case, I use a mixture of WPF data binding paradigm and manual WPF element manipulation. The key
             * point is that this is merely an implementation detail of the view and uses view-specific idioms and
             * "technology". The view model is completely unaware of this, which is good, because usually GUI
             * frameworks are stateful and mutable. */

            this.DataContext = viewModel;

            /* Some things are easier to make not using WPF data binding. The following fragment displays current
             * stamp display order using the corresponding radio buttons. */
            // { none of the radio buttons is checked }, by intention
            if (viewModel.DisplayOrder.Equals(SortedValueHighToLow))
            {
                this.rbSortHighToLow.IsChecked = true;
            }
            else if (viewModel.DisplayOrder.Equals(SortedValueLowToHigh))
            {
                this.rbSortLowToHigh.IsChecked = true;
            }
            else if (viewModel.DisplayOrder.Equals(NotSorted))
            {
                this.rbSortNone.IsChecked = true;
            }
        }
示例#2
0
        /// <summary>
        /// The view sends messages using this method. This method is also used for messages originating from the world
        /// of effectful computations. In a way, this class also belongs to that world...
        /// </summary>
        /// <param name="message"></param>
        internal void SendMessage(Message message)
        {
            // Invoke the dispatching function with current model, current view model and the message.
            var newMandVm = Dispatching.dispatch(this.model, this.viewModel, message);

            // Remember new model and view model as current model and view model, respectively. Observe, that this
            // class doesn't care whether the model or view model actually changed.
            this.model     = newMandVm.Item1;
            this.viewModel = newMandVm.Item2;

            // If the model requested an effectful computation, perform it and route the message back to this function,
            // such that it will be passed to the dispatcher function, exactly the same way as for messages coming from
            // the view.
            var effect = newMandVm.Item3;

            if (effect.IsEffect)
            {
                var e = effect as Effect <Message> .Effect;
                ExecuteEffect(e.Item, this.SendMessage); // executes asynchronously (AE)
            }

            // Send the updated view model to the view. Property (AE) is crucial, because the GUI will not be blocked
            // and the view can assume any intermediate state defined by the view model, until the computation (if any)
            // is done. The example in this demo is simulated verification of stamp rareness, where the view displays a
            // "working on it" feed-back.
            this.viewModelSubject.OnNext(this.viewModel);
        }
示例#3
0
        /// <summary>
        /// Initializes the initial state of the application, consisting of the initial model and initial view model.
        /// </summary>
        /// <remarks>
        /// Note, that as this class is merely a "state holder", it does not create the initial model and view model
        /// itself. This happens in the "main" function of the application.
        /// </remarks>
        /// <param name="initialModel">
        /// The initial model.
        /// </param>
        /// <param name="initialViewModel">
        /// The initial view model.
        /// </param>
        internal ApplicationModel(StampCollection initialModel, StampCollectionViewModel initialViewModel)
        {
            this.model     = initialModel;
            this.viewModel = initialViewModel;

            this.viewModelSubject = new Subject <StampCollectionViewModel>();
        }
        /// <summary>
        /// Initializes the initial state of the application, consisting of the initial model and initial view model.        
        /// </summary>
        /// <remarks>
        /// Note, that as this class is merely a "state holder", it does not create the initial model and view model
        /// itself. This happens in the "main" function of the application.
        /// </remarks>
        /// <param name="initialModel">
        /// The initial model.
        /// </param>
        /// <param name="initialViewModel">
        /// The initial view model.
        /// </param>
        internal ApplicationModel(StampCollection initialModel, StampCollectionViewModel initialViewModel)
        {
            this.model = initialModel;
            this.viewModel = initialViewModel;

            this.viewModelSubject = new Subject<StampCollectionViewModel>();
        }
示例#5
0
        /// <summary>
        /// Initializes the main view (window) and renders the initial view based on the initial view model.
        /// </summary>
        /// <param name="initialViewModel">
        /// The initial view model.
        /// </param>
        /// <param name="applicationModel">
        /// The object which provides updates of the view model and a way of sending messages.
        /// </param>
        public MainWindow(StampCollectionViewModel initialViewModel, ApplicationModel applicationModel)
        {
            InitializeComponent();

            this.applicationModel = applicationModel;

            // Render the initial view.
            this.Render(initialViewModel); // (IR)

            // Subscribe to changes in the view model. Each time a new view model arrives, render it.
            this.applicationModel.ViewModel.Subscribe(this.Render);

            /* We could avoid initial explicit call for initial rendering (IR) by using some fancy Rx subject which
             * sends the initial model already upon subscription. I kept things simple here, because this is an
             * irrelevant implementation detail. */
        }
        /// <summary>
        /// Initializes the main view (window) and renders the initial view based on the initial view model.
        /// </summary>
        /// <param name="initialViewModel">
        /// The initial view model.
        /// </param>
        /// <param name="applicationModel">
        /// The object which provides updates of the view model and a way of sending messages.
        /// </param>
        public MainWindow(StampCollectionViewModel initialViewModel, ApplicationModel applicationModel)
        {
            InitializeComponent();

            this.applicationModel = applicationModel;

            // Render the initial view.
            this.Render(initialViewModel); // (IR)

            // Subscribe to changes in the view model. Each time a new view model arrives, render it.
            this.applicationModel.ViewModel.Subscribe(this.Render);

            /* We could avoid initial explicit call for initial rendering (IR) by using some fancy Rx subject which
             * sends the initial model already upon subscription. I kept things simple here, because this is an
             * irrelevant implementation detail. */
        }
        /// <summary>
        /// The view sends messages using this method. This method is also used for messages originating from the world
        /// of effectful computations. In a way, this class also belongs to that world...
        /// </summary>
        /// <param name="message"></param>
        internal void SendMessage(Message message)
        {
            // Invoke the dispatching function with current model, current view model and the message.
            var newMandVm = Dispatching.dispatch(this.model,this.viewModel, message);

            // Remember new model and view model as current model and view model, respectively. Observe, that this
            // class doesn't care whether the model or view model actually changed.
            this.model = newMandVm.Item1;
            this.viewModel = newMandVm.Item2;

            // If the model requested an effectful computation, perform it and route the message back to this function,
            // such that it will be passed to the dispatcher function, exactly the same way as for messages coming from
            // the view.
            var effect = newMandVm.Item3;
            if (effect.IsEffect)
            {
                var e = effect as Effect<Message>.Effect;
                ExecuteEffect(e.Item, this.SendMessage); // executes asynchronously (AE)
            }

            // Send the updated view model to the view. Property (AE) is crucial, because the GUI will not be blocked
            // and the view can assume any intermediate state defined by the view model, until the computation (if any)
            // is done. The example in this demo is simulated verification of stamp rareness, where the view displays a
            // "working on it" feed-back.
            this.viewModelSubject.OnNext(this.viewModel);
        }
        /// <summary>
        /// Renders the view based on the provided view model.
        /// </summary>
        /// <param name="viewModel">
        /// The view model which must be reflected by the view.
        /// </param>
        private void Render(StampCollectionViewModel viewModel)
        {
            /* In this case, I use a mixture of WPF data binding paradigm and manual WPF element manipulation. The key
             * point is that this is merely an implementation detail of the view and uses view-specific idioms and
             * "technology". The view model is completely unaware of this, which is good, because usually GUI
             * frameworks are stateful and mutable. */

            this.DataContext = viewModel;

            /* Some things are easier to make not using WPF data binding. The following fragment displays current
             * stamp display order using the corresponding radio buttons. */
             // { none of the radio buttons is checked }, by intention
            if (viewModel.DisplayOrder.Equals(SortedValueHighToLow))
            {
                this.rbSortHighToLow.IsChecked = true;
            }
            else if (viewModel.DisplayOrder.Equals(SortedValueLowToHigh))
            {
                this.rbSortLowToHigh.IsChecked = true;
            }
            else if (viewModel.DisplayOrder.Equals(NotSorted))
            {
                this.rbSortNone.IsChecked = true;
            }
        }