﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/css' href='https://stocksharp.com/css/style.css'?>
<?xml-stylesheet type='text/css' href='https://stocksharp.com/css/bbeditor.css'?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html">Создание роботов с помощью S#. Часть 5. Использование паттерна MVVM</title>
  <id>~/topic/355/sozdanie-robotov-s-pomoshshyu-s_-chast-5_-ispolzovanie-patterna-mvvm/</id>
  <rights type="text">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  <updated>2026-06-13T16:40:17Z</updated>
  <logo>https://stocksharp.com/images/logo.png</logo>
  <link href="https://stocksharp.com/handlers/atom.ashx?category=topic&amp;id=355" rel="self" type="application/rss+xml" />
  <entry>
    <id>https://stocksharp.com/posts/m/137/</id>
    <title type="text">Можно было бы уже остановиться на достигнутом. Но бородатые дяди в очках все время придумывают какие...</title>
    <published>2012-03-18T21:59:03Z</published>
    <updated>2012-12-17T15:06:40Z</updated>
    <author>
      <name>FinDirector</name>
      <uri>https://stocksharp.com/users/473/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Можно было бы уже остановиться на достигнутом. Но бородатые дяди в очках все время придумывают какие-то серебрянные пули. Видите ли, уважаемый программист не будет писать кучу кода в форме, а будет использовать паттерн MVVM (Model-View-ViewModel). Не существует какого-то единственно правильного способа реализовать этот паттерн, поэтому предлагаю самый простейший вариант.
Нам понадобится интерфейс IVIew и базовый класс для ViewModel:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;	public interface IView
	{
		object DataContext { get; set; }
	}

	public abstract class ViewModel : INotifyPropertyChanged
	{
		public IView View { get; protected set; }

		protected ViewModel() { }

		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		protected void RaisePropertyChanged(string propertyName)
		{
			PropertyChangedEventHandler handler = PropertyChanged;
			if (handler == null) return;
			handler(this, new PropertyChangedEventArgs(propertyName));
		}

		#endregion
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В нашем простом приложении будет две View и две ViewModel.
&lt;strong&gt;StrategyViewModel.cs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;	class StrategyViewModel : ViewModel
	{
		public StandardStrategy Strategy { get; private set; }
		public DelegateCommand StartCommand { get; private set; }
		public DelegateCommand StopCommand { get; private set; }
		public DelegateCommand RunTerminalCommand { get; private set; }

		public StrategyViewModel(StandardStrategy strategy)
		{
			this.Strategy = strategy;

			this.StartCommand = new DelegateCommand(OnStartExecuted, CanStart);
			this.StopCommand = new DelegateCommand(OnStopExecuted, CanStop);
			this.RunTerminalCommand = new DelegateCommand(RunTerminal);
			this.Strategy.ProcessStateChanged += s =&amp;gt;
			{
				this.StartCommand.RaiseCanExecuteChanged();
				this.StopCommand.RaiseCanExecuteChanged();
			};

			this.View = new StrategyView();
			this.View.DataContext = this;
		}

		public bool CanStart()
		{
			return Strategy.ProcessState == ProcessStates.Stopped;
		}

		public void OnStartExecuted()
		{
			if (!CanStart())
				return;
			Task.Factory.StartNew(Strategy.Start);
		}

		public bool CanStop()
		{
			return Strategy.ProcessState == ProcessStates.Started;
		}

		public void OnStopExecuted()
		{
			if (!CanStop())
				return;
			MessageBoxResult result = MessageBox.Show(
				String.Format(&amp;quot;Вы уверены, что хотите остановить стратегию {0}?&amp;quot;, Strategy.Name),
				&amp;quot;Подтверждение&amp;quot;, MessageBoxButton.OKCancel);
			if (result == MessageBoxResult.OK)
				Strategy.Stop();
		}

		public void RunTerminal()
		{
			MessageBoxResult result = MessageBox.Show(
				String.Format(&amp;quot;Вы уверены, что хотите запустить терминал {0}?&amp;quot;, Strategy.TraderBuilder.Title),
				&amp;quot;Подтверждение&amp;quot;, MessageBoxButton.OKCancel);
			if (result == MessageBoxResult.OK)
				Strategy.TraderBuilder.RunTerminal();
		}
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;StrategyView помечаем интерфейсом IView:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;StrategyView.xaml.cs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;	public partial class StrategyView : UserControl, IView
	{
		public StrategyView()
		{
			InitializeComponent();
		}
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;StrategyView.xaml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-xml"&gt;    &amp;lt;UserControl.Resources&amp;gt;
        &amp;lt;Style x:Key=&amp;quot;stValue&amp;quot; TargetType=&amp;quot;FrameworkElement&amp;quot;&amp;gt;
            &amp;lt;Setter Property=&amp;quot;HorizontalAlignment&amp;quot; Value=&amp;quot;Right&amp;quot; /&amp;gt;
        &amp;lt;/Style&amp;gt;
    &amp;lt;/UserControl.Resources&amp;gt;
    &amp;lt;StackPanel Margin=&amp;quot;3&amp;quot;&amp;gt;
        &amp;lt;StackPanel Margin=&amp;quot;5&amp;quot;&amp;gt;
            &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.Name}&amp;quot; FontSize=&amp;quot;14&amp;quot; /&amp;gt;
            &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.Description}&amp;quot; FontSize=&amp;quot;9&amp;quot;  /&amp;gt;
            &amp;lt;Grid&amp;gt;
                &amp;lt;Grid.ColumnDefinitions&amp;gt;
                    &amp;lt;ColumnDefinition /&amp;gt;
                    &amp;lt;ColumnDefinition /&amp;gt;
                &amp;lt;/Grid.ColumnDefinitions&amp;gt;
                &amp;lt;Grid.RowDefinitions&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                    &amp;lt;RowDefinition /&amp;gt;
                &amp;lt;/Grid.RowDefinitions&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;Терминал: &amp;quot; Grid.Row=&amp;quot;0&amp;quot; Grid.Column=&amp;quot;0&amp;quot; /&amp;gt;
                &amp;lt;Button Grid.Row=&amp;quot;0&amp;quot; Grid.Column=&amp;quot;1&amp;quot;
                                        HorizontalAlignment=&amp;quot;Right&amp;quot;
                                        Content=&amp;quot;{Binding Strategy.TraderBuilder.Title}&amp;quot;
                                        Command=&amp;quot;{Binding Path=RunTerminalCommand}&amp;quot; /&amp;gt;

                &amp;lt;TextBlock Text=&amp;quot;Портфель: &amp;quot; Grid.Row=&amp;quot;1&amp;quot; Grid.Column=&amp;quot;0&amp;quot; /&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.PortfolioSelector.Title}&amp;quot; Grid.Row=&amp;quot;1&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Style=&amp;quot;{StaticResource stValue}&amp;quot;/&amp;gt;

                &amp;lt;TextBlock Text=&amp;quot;Инструмент: &amp;quot; Grid.Row=&amp;quot;2&amp;quot; Grid.Column=&amp;quot;0&amp;quot; /&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.SecuritySelector.Title}&amp;quot; Grid.Row=&amp;quot;2&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Style=&amp;quot;{StaticResource stValue}&amp;quot;/&amp;gt;

                &amp;lt;TextBlock Text=&amp;quot;Состояние: &amp;quot; Grid.Row=&amp;quot;3&amp;quot; Grid.Column=&amp;quot;0&amp;quot; /&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.ProcessState}&amp;quot; Grid.Row=&amp;quot;3&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Style=&amp;quot;{StaticResource stValue}&amp;quot;/&amp;gt;

                &amp;lt;TextBlock Text=&amp;quot;Прибыль: &amp;quot; Grid.Row=&amp;quot;4&amp;quot; Grid.Column=&amp;quot;0&amp;quot;/&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.PnLManager.PnL}&amp;quot; Grid.Row=&amp;quot;4&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Style=&amp;quot;{StaticResource stValue}&amp;quot;/&amp;gt;

                &amp;lt;TextBlock Text=&amp;quot;Позиция: &amp;quot; Grid.Row=&amp;quot;5&amp;quot; Grid.Column=&amp;quot;0&amp;quot;/&amp;gt;
                &amp;lt;TextBlock Text=&amp;quot;{Binding Strategy.PositionManager.Position}&amp;quot; Grid.Row=&amp;quot;5&amp;quot; Grid.Column=&amp;quot;1&amp;quot; Style=&amp;quot;{StaticResource stValue}&amp;quot;/&amp;gt;
            &amp;lt;/Grid&amp;gt;
            &amp;lt;StackPanel Orientation=&amp;quot;Horizontal&amp;quot; Margin=&amp;quot;0,5,0,0&amp;quot; HorizontalAlignment=&amp;quot;Center&amp;quot;&amp;gt;
                &amp;lt;Button x:Name=&amp;quot;btnStartStrategy&amp;quot; Content=&amp;quot;Старт&amp;quot; Command=&amp;quot;{Binding Path=StartCommand}&amp;quot; Margin=&amp;quot;2,0,0,0&amp;quot; /&amp;gt;
                &amp;lt;Button x:Name=&amp;quot;btnStopStrategy&amp;quot; Content=&amp;quot;Стоп&amp;quot; Command=&amp;quot;{Binding Path=StopCommand}&amp;quot; Margin=&amp;quot;2,0,0,0&amp;quot; /&amp;gt;
            &amp;lt;/StackPanel&amp;gt;
        &amp;lt;/StackPanel&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MainViewModel.cs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;	class MainViewModel : IDisposable
	{
		public ObservableCollection&amp;lt;StrategyViewModel&amp;gt; Strategies { get; private set; }
		public ILogListener LogView { get; private set; }
		private LogManager LogManager;

		public MainViewModel()
		{
			Strategies = new ObservableCollection&amp;lt;StrategyViewModel&amp;gt;();
			CreateLoggers();
		}

		private void CreateLoggers()
		{
			LogManager = new LogManager();

			LogView = new StockSharp.Xaml.Monitor();
			LogManager.Listeners.Add(LogView);

			var fileListener = new FileLogListener(
				string.Format(CultureInfo.InvariantCulture, &amp;quot;{0:yyyyMMdd}.txt&amp;quot;, DateTime.Today));
			LogManager.Listeners.Add(fileListener);

			if (!string.IsNullOrEmpty(Settings.GoogleLogin))
			{
				var smsListener = new SmsLogListener(Settings.GoogleLogin, Settings.GooglePassword);
				smsListener.Filters.Add(LogListener.AllErrorFilter);
				LogManager.Listeners.Add(smsListener);
			}
		}

		public void Dispose()
		{
			if (LogManager != null)
				LogManager.Dispose();
			if (Strategies != null)
			{
				foreach (ITraderBuilder traderBuilder in Strategies.Select(s =&amp;gt; s.Strategy.TraderBuilder).Distinct())
				{
					if (traderBuilder != null)
						traderBuilder.Dispose();
				}
			}
		}

		public void LoadStrategies()
		{
			StrategyLoader strategyLoader = StrategyLoader.Load(&amp;quot;Strategies.config&amp;quot;);
			Strategies.Clear();
			foreach (StandardStrategy strategy in strategyLoader.Strategies)
			{
				LogManager.Sources.Add(strategy);
				StrategyViewModel strategyModel = new StrategyViewModel(strategy);
				Strategies.Add(strategyModel);
			}
			foreach (ILogSource logSource in strategyLoader.Strategies
				.Select(s =&amp;gt; s.TraderBuilder).OfType&amp;lt;ILogSource&amp;gt;().Distinct())
			{
				LogManager.Sources.Add(logSource);
			}
		}
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MainWindow.xaml.cs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;	public partial class MainWindow : Window
	{
		private MainViewModel viewModel;

		public MainWindow()
		{
			InitializeComponent();
			this.Loaded += Window_Loaded;

			this.viewModel = new MainViewModel();
			this.DataContext = viewModel;
		}

		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			viewModel.LoadStrategies();
		}

		protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
		{
			base.OnClosing(e);
			MessageBoxResult result = MessageBox.Show(
				&amp;quot;Вы уверены, что хотите завершить работу?&amp;quot;,
				&amp;quot;Подтверждение&amp;quot;, MessageBoxButton.OKCancel);
			if (result != MessageBoxResult.OK)
				e.Cancel = true;
		}

		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			if (viewModel != null)
				viewModel.Dispose();
		}
	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MainWindow.xaml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-xml"&gt;    &amp;lt;Grid&amp;gt;
        &amp;lt;Grid.RowDefinitions&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot;/&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot;/&amp;gt;
        &amp;lt;/Grid.RowDefinitions&amp;gt;

        &amp;lt;ScrollViewer Grid.Row=&amp;quot;0&amp;quot; VerticalScrollBarVisibility=&amp;quot;Auto&amp;quot;&amp;gt;
            &amp;lt;ItemsControl ItemsSource=&amp;quot;{Binding Path=Strategies}&amp;quot;&amp;gt;
                &amp;lt;ItemsControl.ItemsPanel&amp;gt;
                    &amp;lt;ItemsPanelTemplate&amp;gt;
                        &amp;lt;WrapPanel &amp;gt;&amp;lt;/WrapPanel&amp;gt;
                    &amp;lt;/ItemsPanelTemplate&amp;gt;
                &amp;lt;/ItemsControl.ItemsPanel&amp;gt;
                &amp;lt;ItemsControl.ItemTemplate&amp;gt;
                    &amp;lt;DataTemplate&amp;gt;
                        &amp;lt;ContentControl Content=&amp;quot;{Binding View}&amp;quot; /&amp;gt;
                    &amp;lt;/DataTemplate&amp;gt;
                &amp;lt;/ItemsControl.ItemTemplate&amp;gt;
            &amp;lt;/ItemsControl&amp;gt;
        &amp;lt;/ScrollViewer&amp;gt;

        &amp;lt;ContentControl Grid.Row=&amp;quot;1&amp;quot; Content=&amp;quot;{Binding LogView}&amp;quot; /&amp;gt;
    &amp;lt;/Grid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Остается добавить к приложению стили и оно станет выглядеть как в статье &lt;a href="http://stocksharp.com/algo/article.aspx?aid=4"&gt;“Создание роботов с помощью S#. Введение”&lt;/a&gt;.&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/22746/</id>
    <title type="text">Автор использовал using Microsoft.Practices.Prism.Commands; http://compositewpf.codeplex.com/release...</title>
    <published>2012-11-30T17:41:08Z</published>
    <updated>2012-11-30T17:41:08Z</updated>
    <author>
      <name>VassilSanych</name>
      <uri>https://stocksharp.com/users/6491/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Автор использовал
using Microsoft.Practices.Prism.Commands;
&lt;a href="http://compositewpf.codeplex.com/releases/view/95815" rel="nofollow" target="_blank"&gt;http://compositewpf.codeplex.com/releases/view/95815&lt;/a&gt;&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20435/</id>
    <title type="text">По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет. То, что хорошо при напис...</title>
    <published>2012-07-19T10:44:37Z</published>
    <updated>2012-07-19T10:44:37Z</updated>
    <author>
      <name>VassilSanych</name>
      <uri>https://stocksharp.com/users/6491/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет.
То, что хорошо при написании калькулятора, может не подойти при написании реального приложения.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;В &amp;quot;реальном приложении&amp;quot; обычно бывает так:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;архитектор/ведущий разработчик/etc  накрутил 4 звена, в каждом по 5 &amp;quot;правильных&amp;quot; слоёв (действительно правильных со стройной архитектурой),&lt;/li&gt;
&lt;li&gt;документацию по архитектуре ему писать либо лень, либо &amp;quot;потом напишу&amp;quot;, либо она просто устаревает намного быстрее полёта его мысли,&lt;/li&gt;
&lt;li&gt;в команде 10-20 разработчиков,&lt;/li&gt;
&lt;li&gt;все более-менее в курсе зон ответственности звеньев (архитектор за этим старается следить, да VS не даст использовать зависимости чужого звена), но не особо разбираются в идеях зон ответственности слоёв&lt;/li&gt;
&lt;li&gt;соответственно при кодировании зоны ответственности слоёв нарушаются, в проекте хренова туча кода - за каждым не уследишь (при том, что всё замечательно работает и проходит все тесты)&lt;/li&gt;
&lt;li&gt;на выходе имеем жесточайший бардак в проекте -&amp;gt; проблемы с рефакторингом -&amp;gt; медленная и мучительная смерть проекта&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;quot;Сделай настолько просто, насколько это возможно, но не проще.&amp;quot; Эйнштейн&lt;/p&gt;
&lt;p&gt;PS
Я видел это в коде бизнес-приложения Microsoft, например. Кстати это тоже было интеграционное решение, как и StockSharp. C похожими проблемами политики качества (Для обеспечения регрессионного тестирования таких приложений нужно примерно в 3 раза больше ресурсов, чем собственно для создания приложения. Причём ресурсов как минимум такого же качества).&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20354/</id>
    <title type="text">По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет. Вот пример ответа на sta...</title>
    <published>2012-07-14T10:04:44Z</published>
    <updated>2012-07-14T10:04:44Z</updated>
    <author>
      <name>anothar</name>
      <uri>https://stocksharp.com/users/6089/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет.
Вот пример ответа на stackoverflow.com:&lt;a href="http://stackoverflow.com/questions/2798447/is-mvvm-pointless" rel="nofollow" target="_blank"&gt;wpf mvvm&lt;/a&gt;. Любой паттерн служит определенной цели и модели построения приложений. Нужно его применять там, где он будет востребован и приносить пользу.
А цель программирования, как известно, - борьба со сложностью.
Сложности бывают как известно разные. То, что хорошо при написании калькулятора, может не подойти при написании реального приложения.
Хорошо бы еще раскрыть в статье использование каких-то известных фреймворков типа Prism, Caliburn и т.д.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20350/</id>
    <title type="text">VassilSanych: По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет. Потому что...</title>
    <published>2012-07-13T16:01:45Z</published>
    <updated>2012-07-13T16:01:45Z</updated>
    <author>
      <name>ra81</name>
      <uri>https://stocksharp.com/users/16581/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="@message(20348)" rel="nofollow" target="_blank"&gt;VassilSanych&lt;/a&gt;:&lt;/strong&gt;
По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет. Потому что WPF и так организован по принципу MVVM.
Если системы делаются в виде отдельных библиотек включающих код и отображение, без паттерна не обойтись. Интеграция библиотеки в общую оболочку может встать дорого :). Я тоже реализовал себе сей паттерн. Меня устраиват полностью.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20349/</id>
    <title type="text">ra81: Сама стратегия оформляется в виде библиотеки. Кстати. Никто не пробовал csscript? </title>
    <published>2012-07-13T15:43:32Z</published>
    <updated>2012-07-13T15:43:32Z</updated>
    <author>
      <name>VassilSanych</name>
      <uri>https://stocksharp.com/users/6491/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="@message(20074)" rel="nofollow" target="_blank"&gt;ra81&lt;/a&gt;:&lt;/strong&gt;
Сама стратегия оформляется в виде библиотеки.
Кстати.
Никто не пробовал &lt;a href="http://www.csscript.net/" rel="nofollow" target="_blank"&gt;csscript&lt;/a&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20348/</id>
    <title type="text">Но вообще-то это была шутка (хотя в контексте статьи шуткой и не является). Сейчас объясню почему. П...</title>
    <published>2012-07-13T15:23:42Z</published>
    <updated>2012-07-13T15:39:34Z</updated>
    <author>
      <name>VassilSanych</name>
      <uri>https://stocksharp.com/users/6491/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Но вообще-то это была шутка (хотя в контексте статьи шуткой и не является).
Сейчас объясню почему.
По моему скромному мнению, накручивать ViewModel в WPF большого смысла нет. Потому что WPF и так организован по принципу MVVM.
Где behind code является фактически этим самым ViewModel (в отличии от форм WinForms), потому что он уже слабо отвечает за отображение формы (должен слабо отвечать), а больше отвечает за её поведение. А в процессе отображения уже участвует не только behind code, но и куча сервисов собственно WPF.
В общем в контексте WPF: view - это XAML, viewModel - это behind code, а model - это собственно модель.
Накручивать свои архитектурные нахлобучки на WPF конечно можно (&amp;quot;Любую проблему можно решить введением дополнительного уровня абстракции, кроме проблемы слишком большого количества уровней абстракции&amp;quot; :)  )
Но, как показывает практика, это обычно усложняет систему и увеличивает трудоёмкость (даже в очень крупных системах). А цель программирования, как известно, - борьба со сложностью.
;)&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20347/</id>
    <title type="text">Где, где у нас ```csharp new MainViewModel() В ```csharp MainWindow : Window ```? WinForms Hell dete...</title>
    <published>2012-07-13T14:18:23Z</published>
    <updated>2012-07-13T14:18:23Z</updated>
    <author>
      <name>VassilSanych</name>
      <uri>https://stocksharp.com/users/6491/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Где, где у нас ```csharp
new MainViewModel()&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-?"&gt;В ```csharp
MainWindow : Window
```?
WinForms Hell detected :)
MVVM и рядом не стояло. Даже на MVP не тянет :)
&lt;/code&gt;&lt;/pre&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20082/</id>
    <title type="text">Спасибо за ответ. Все просто и наглядно. </title>
    <published>2012-06-30T14:59:07Z</published>
    <updated>2012-06-30T14:59:07Z</updated>
    <author>
      <name>AlexLan73</name>
      <uri>https://stocksharp.com/users/6005/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Спасибо за ответ.
Все просто и наглядно.&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20074/</id>
    <title type="text">AlexLan73: Замечательные примеры. Большое Вам спасибо. А Вы можете сделать пример - вывод индикаторо...</title>
    <published>2012-06-30T08:00:02Z</published>
    <updated>2012-06-30T08:00:02Z</updated>
    <author>
      <name>ra81</name>
      <uri>https://stocksharp.com/users/16581/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="@message(20068)" rel="nofollow" target="_blank"&gt;AlexLan73&lt;/a&gt;:&lt;/strong&gt;
Замечательные примеры.
Большое Вам спасибо.
А Вы можете сделать пример - вывод индикаторов RSI, MACD ... в новом окне?
Я сделал несколько иначе. Сама стратегия оформляется в виде библиотеки. Библиотека подключается в общую систему, в ней же лежит визуализацию самой стратегии. В том числе и кнопка и график.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;По сути система это коробка, куда пихаются кубики.&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
  <entry>
    <id>https://stocksharp.com/posts/m/20068/</id>
    <title type="text">Замечательные примеры. Большое Вам спасибо. А Вы можете сделать пример - вывод индикаторов RSI, MACD...</title>
    <published>2012-06-29T17:56:48Z</published>
    <updated>2012-06-29T17:56:48Z</updated>
    <author>
      <name>AlexLan73</name>
      <uri>https://stocksharp.com/users/6005/</uri>
      <email>info@stocksharp.com</email>
    </author>
    <content type="html">&lt;p&gt;Замечательные примеры.
Большое Вам спасибо.
А Вы можете сделать пример - вывод индикаторов RSI, MACD ... в новом окне?&lt;/p&gt;
</content>
    <rights type="html">Copyright @ StockSharp Platform LLC 2010 - 2025</rights>
  </entry>
</feed>