DM-V-VM

来源:互联网 发布:java buffer转string 编辑:程序博客网 时间:2024/06/05 04:33
using System;using System.Collections.Generic;using System.Text;namespace ModelSample{    /// <summary>    /// Interface for a provider of stock quotes.    /// </summary>    public interface IStockQuoteProvider    {        /// <summary>        /// Get a quote. This function may block on slow operations like hitting the network.        /// </summary>        /// <param name="symbol">The stock symbol.</param>        /// <param name="quote">The quote.</param>        /// <returns>Whether we were able to get a quote.</returns>        bool TryGetQuote(string symbol, out double quote);    }}

using System;using System.Collections.Generic;using System.Text;namespace ModelSample{    /// <summary>    /// Mock IStockQuoteProvider that alwyas returns 100.    /// </summary>    public class MockQuoteProvider : IStockQuoteProvider    {        public bool TryGetQuote(string symbol, out double quote)        {            quote = 100.0;            return true;        }    }}

using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Text;using System.Windows.Input;namespace ModelSample{    /// <summary>    /// View model for the portfolio view    /// </summary>    public class PortfolioViewModel    {        public PortfolioViewModel(IStockQuoteProvider quoteProvider)        {            _quoteProvider = quoteProvider;            _stockModels = new ObservableCollection<StockModel>();            _stockModels.Add(new StockModel("MSFT", _quoteProvider));            _addCommand = new AddCommand(this);            _removeCommand = new RemoveCommand(this);        }        /// <summary>        /// The list of StockModels for the page.        /// </summary>        public ObservableCollection<StockModel> Stocks        {            get { return _stockModels; }        }        /// <summary>        /// A CommandModel for Add. The command parameter should be the symbol to add.        /// </summary>        public CommandModel AddCommandModel        {            get { return _addCommand; }        }        /// <summary>        /// A CommandModel for Remove. The command parameter should be the StockModel to remove.        /// </summary>        public CommandModel RemoveCommandModel        {            get { return _removeCommand; }        }        /// <summary>        /// Private implementation of the Add Command        /// </summary>        private class AddCommand : CommandModel        {            public AddCommand(PortfolioViewModel viewModel)            {                _viewModel = viewModel;            }            public override void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e)            {                string symbol = e.Parameter as string;                e.CanExecute = (!string.IsNullOrEmpty(symbol));                e.Handled = true;            }            public override void OnExecute(object sender, ExecutedRoutedEventArgs e)            {                string symbol = e.Parameter as string;                _viewModel._stockModels.Add(new StockModel(symbol, _viewModel._quoteProvider));                }            private PortfolioViewModel _viewModel;        }        /// <summary>        /// Private implementation of the Remove command        /// </summary>        private class RemoveCommand : CommandModel        {            public RemoveCommand(PortfolioViewModel viewModel)            {                _viewModel = viewModel;            }            public override void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e)            {                e.CanExecute = e.Parameter is StockModel;                e.Handled = true;            }            public override void OnExecute(object sender, ExecutedRoutedEventArgs e)            {                _viewModel._stockModels.Remove(e.Parameter as StockModel);            }            private PortfolioViewModel _viewModel;        }        private ObservableCollection<StockModel> _stockModels;        private CommandModel _addCommand;        private CommandModel _removeCommand;        private IStockQuoteProvider _quoteProvider;    }}

using System;using System.ComponentModel;using System.Diagnostics;using System.Threading;using System.Windows.Threading;namespace ModelSample{    public class StockModel : DataModel    {        public StockModel(string symbol, IStockQuoteProvider quoteProvider)        {            _symbol = symbol;            _quoteProvider = quoteProvider;        }        protected override void OnActivated()        {            VerifyCalledOnUIThread();            base.OnActivated();            _timer = new DispatcherTimer(DispatcherPriority.Background);            _timer.Interval = TimeSpan.FromMinutes(5);            _timer.Tick += delegate { ScheduleUpdate(); };            _timer.Start();            ScheduleUpdate();        }        protected override void OnDeactivated()        {            VerifyCalledOnUIThread();            base.OnDeactivated();            _timer.Stop();            _timer = null;        }        private void ScheduleUpdate()        {            VerifyCalledOnUIThread();            // Queue a work item to fetch the quote            if (ThreadPool.QueueUserWorkItem(new WaitCallback(FetchQuoteCallback)))            {                this.State = ModelState.Fetching;            }        }        /// <summary>        /// Gets the stock symbol.        /// </summary>        public string Symbol        {            get { return _symbol; }        }        /// <summary>        /// Gets the current quote for the stock. Only valid if State == Active.        /// </summary>        public double Quote        {            get            {                VerifyCalledOnUIThread();                return _quote;            }            private set            {                VerifyCalledOnUIThread();                if (_quote != value)                {                    _quote = value;                    SendPropertyChanged("Quote");                }            }        }        /// <summary>        /// Callback on background thread to fecth quote.        /// </summary>        private void FetchQuoteCallback(object state)        {            double fetchedQuote;            if (_quoteProvider.TryGetQuote(_symbol, out fetchedQuote))            {                this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ThreadStart(delegate                    {                        this.Quote = fetchedQuote;                        this.State = ModelState.Valid;                    }));            }            else            {                this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ThreadStart(delegate                    { this.State = ModelState.Invalid; }));            }        }        private string _symbol;        private double _quote;        private IStockQuoteProvider _quoteProvider;        private DispatcherTimer _timer;    }}

<Window x:Class="ModelSample.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    Title="ModelSample" Height="300" Width="300"    >    <Grid>      <ContentControl x:Name="_content" />    </Grid></Window>



using System;using System.Collections.Generic;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;namespace ModelSample{    /// <summary>    /// Interaction logic for Window1.xaml    /// </summary>    public partial class Window1 : Window    {        public Window1()        {            InitializeComponent();            _content.Content = new PortfolioViewModel(new MockQuoteProvider());        }    }}


<Application x:Class="ModelSample.App"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="clr-namespace:ModelSample"     StartupUri="Window1.xaml"    >  <Application.Resources>    <!-- Data Template for individual stocks -->    <DataTemplate DataType="{x:Type local:StockModel}">      <StackPanel Orientation="Horizontal" local:ActivateModel.Model="{Binding}">        <TextBlock Text="{Binding Symbol}" Width="100"/>        <TextBlock Text="{Binding Quote}" />      </StackPanel>    </DataTemplate>    <!-- Definition of Portfolio view -->    <DataTemplate DataType="{x:Type local:PortfolioViewModel}">      <DockPanel LastChildFill="True">        <TextBlock DockPanel.Dock="Top" TextAlignment="Center">Portfolio View</TextBlock>        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">          <TextBox Name="AddSymbol" Width="100" />          <Button Command="{Binding AddCommandModel.Command}"                  CommandParameter="{Binding Path=Text,ElementName=AddSymbol}"                  local:CreateCommandBinding.Command="{Binding AddCommandModel}"                  >            Add            </Button>          <Button Margin="50,0,0,0"                  Command="{Binding RemoveCommandModel.Command}"                  CommandParameter="{Binding Path=SelectedItem,ElementName=StockList}"                  local:CreateCommandBinding.Command="{Binding RemoveCommandModel}"                  >            Remove          </Button>        </StackPanel>        <ListBox Name="StockList" ItemsSource="{Binding Stocks}" />      </DockPanel>    </DataTemplate>  </Application.Resources></Application>



using System;using System.Collections.Generic;using System.Text;using System.Windows.Input;namespace ModelSample{    /// <summary>    /// Model for a command    /// </summary>    public abstract class CommandModel    {        public CommandModel()        {            _routedCommand = new RoutedCommand();        }        /// <summary>        /// Routed command associated with the model.        /// </summary>        public RoutedCommand Command        {            get { return _routedCommand; }        }        /// <summary>        /// Determines if a command is enabled. Override to provide custom behavior. Do not call the        /// base version when overriding.        /// </summary>        public virtual void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e)        {            e.CanExecute = true;            e.Handled = true;        }        /// <summary>        /// Function to execute the command.        /// </summary>        public abstract void OnExecute(object sender, ExecutedRoutedEventArgs e);        private RoutedCommand _routedCommand;    }}

using System;using System.Collections.Generic;using System.Text;using System.Windows;using System.Windows.Input;namespace ModelSample{    /// <summary>    /// Attached property that can be used to create a binding for a CommandModel. Set the    /// CreateCommandBinding.Command property to a CommandModel.    /// </summary>    public static class CreateCommandBinding    {        public static readonly DependencyProperty CommandProperty           = DependencyProperty.RegisterAttached("Command", typeof(CommandModel), typeof(CreateCommandBinding),                new PropertyMetadata(new PropertyChangedCallback(OnCommandInvalidated)));        public static CommandModel GetCommand(DependencyObject sender)        {            return (CommandModel)sender.GetValue(CommandProperty);        }        public static void SetCommand(DependencyObject sender, CommandModel command)        {            sender.SetValue(CommandProperty, command);        }        /// <summary>        /// Callback when the Command property is set or changed.        /// </summary>        private static void OnCommandInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)        {            // Clear the exisiting bindings on the element we are attached to.            UIElement element = (UIElement)dependencyObject;            element.CommandBindings.Clear();            // If we're given a command model, set up a binding            CommandModel commandModel = e.NewValue as CommandModel;            if (commandModel != null)            {                element.CommandBindings.Add(new CommandBinding(commandModel.Command, commandModel.OnExecute, commandModel.OnQueryEnabled));            }            // Suggest to WPF to refresh commands            CommandManager.InvalidateRequerySuggested();        }    }}

using System;using System.ComponentModel;using System.Diagnostics;using System.Windows.Threading;namespace ModelSample{    /// <summary>    /// Base class for data models. All public methods must be called on the UI thread only.    /// </summary>    public class DataModel : INotifyPropertyChanged    {        public DataModel()        {            _dispatcher = Dispatcher.CurrentDispatcher;            this.State = ModelState.Invalid;        }        /// <summary>        /// Possible states for a DataModel.        /// </summary>        public enum ModelState        {            Invalid,    // The model is in an invalid state            Fetching,   // The model is being fetched            Valid       // The model has fetched its data        }        /// <summary>        /// Is the model active?        /// </summary>        public bool IsActive        {            get            {                VerifyCalledOnUIThread();                return _isActive;            }            private set            {                VerifyCalledOnUIThread();                if (value != _isActive)                {                    _isActive = value;                    SendPropertyChanged("IsActive");                }            }        }        /// <summary>        /// Activate the model.        /// </summary>        public void Activate()        {            VerifyCalledOnUIThread();            if (!_isActive)            {                this.IsActive = true;                OnActivated();            }        }        /// <summary>        /// Override to provide behavior on activate.        /// </summary>        protected virtual void OnActivated()        {        }        /// <summary>        /// Deactivate the model.        /// </summary>        public void Deactivate()        {            VerifyCalledOnUIThread();            if (_isActive)            {                this.IsActive = false;                OnDeactivated();            }        }        /// <summary>        /// Override to provide behavior on deactivate.        /// </summary>        protected virtual void OnDeactivated()        {        }        /// <summary>        /// PropertyChanged event for INotifyPropertyChanged implementation.        /// </summary>        public event PropertyChangedEventHandler PropertyChanged        {            add            {                VerifyCalledOnUIThread();                _propertyChangedEvent += value;            }            remove            {                VerifyCalledOnUIThread();                _propertyChangedEvent -= value;            }        }        /// <summary>        /// Gets or sets current state of the model.        /// </summary>        public ModelState State        {            get            {                VerifyCalledOnUIThread();                return _state;            }            set            {                VerifyCalledOnUIThread();                if (value != _state)                {                    _state = value;                    SendPropertyChanged("State");                }            }        }        /// <summary>        /// The Dispatcher associated with the model.        /// </summary>        public Dispatcher Dispatcher        {            get { return _dispatcher; }        }        /// <summary>        /// Utility function for use by subclasses to notify that a property has changed.        /// </summary>        /// <param name="propertyName">The name of the property.</param>        protected void SendPropertyChanged(string propertyName)        {            VerifyCalledOnUIThread();            if (_propertyChangedEvent != null)            {                _propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));            }        }        /// <summary>        /// Debugging utility to make sure functions are called on the UI thread.        /// </summary>        [Conditional("Debug")]        protected void VerifyCalledOnUIThread()        {            Debug.Assert(Dispatcher.CurrentDispatcher == this.Dispatcher, "Call must be made on UI thread.");        }        private ModelState _state;        private Dispatcher _dispatcher;        private PropertyChangedEventHandler _propertyChangedEvent;        private bool _isActive;    }}


using System;using System.Collections.Generic;using System.Diagnostics;using System.Text;using System.Windows;namespace ModelSample{    /// <summary>    /// Attached property that can be used to activate a model.    /// </summary>    public static class ActivateModel    {        public static readonly DependencyProperty ModelProperty           = DependencyProperty.RegisterAttached("Model", typeof(DataModel), typeof(ActivateModel),                new PropertyMetadata(new PropertyChangedCallback(OnModelInvalidated)));        public static DataModel GetModel(DependencyObject sender)        {            return (DataModel)sender.GetValue(ModelProperty);        }        public static void SetModel(DependencyObject sender, DataModel model)        {            sender.SetValue(ModelProperty, model);        }        /// <summary>        /// Callback when the Model property is set or changed.        /// </summary>        private static void OnModelInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)        {            FrameworkElement element = (FrameworkElement)dependencyObject;            // Add handlers if necessary            if (e.OldValue == null && e.NewValue != null)            {                element.Loaded += OnElementLoaded;                element.Unloaded += OnElementUnloaded;            }            // Or, remove if necessary            if (e.OldValue != null && e.NewValue == null)            {                element.Loaded -= OnElementLoaded;                element.Unloaded -= OnElementUnloaded;            }            // If loaded, deactivate old model and activate new one            if (element.IsLoaded)            {                if (e.OldValue != null)                {                    ((DataModel)e.OldValue).Deactivate();                }                if (e.NewValue != null)                {                    ((DataModel)e.NewValue).Activate();                }            }        }         /// <summary>        /// Activate the model when the element is loaded.        /// </summary>        static void OnElementLoaded(object sender, RoutedEventArgs e)        {            FrameworkElement element = (FrameworkElement)sender;            DataModel model = GetModel(element);            model.Activate();        }        /// <summary>        /// Deactivate the model when the element is unloaded.        /// </summary>        static void OnElementUnloaded(object sender, RoutedEventArgs e)        {            FrameworkElement element = (FrameworkElement)sender;            DataModel model = GetModel(element);            model.Deactivate();        }    }}




原创粉丝点击