← Atrás

Импорт таблицы перестал работать

Код состоит из следующих элементов:


private QuikTrader _trader;
private readonly MyTradesWindow _myTradesWindow = new MyTradesWindow();
_trader.NewMyTrades += trades => this.GuiAsync(() => _myTradesWindow.Trades.AddRange(trades));

string tstr = "А вот и мои сделочки: \n";
foreach (var myTrade in _myTradesWindow.Trades)
{
    var trade = myTrade.Trade;
    tstr = tstr + string.Format("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.\n", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
}
tradestb.Text = tstr;

В итоге в TextBox выводится только инициализированная строка tstr, без сделок. Весь день ушёл на поиск причины, хотя ещё в пятницу табличка выводилась. Код не менял. В то же время стакан, например, выводится как надо. В чём может быть проблема?

¿Le resultó útil este tema?

Compartir tema

Comentarios (24)

Iniciar sesión o Crear cuenta, Inicie sesión o regístrese para dejar un comentario

Den
Den

Творог: В итоге в TextBox выводится только инициализированная строка tstr, без сделок. Весь день ушёл на поиск причины, хотя ещё в пятницу табличка выводилась. Код не менял. В то же время стакан, например, выводится как надо. В чём может быть проблема?

Трейдер синхронный или нет?

Возможно причина та же самая, что и у меня: не приходит newStopOrders

Творог
Творог Autor

Den: Трейдер синхронный или нет?

Возможно причина та же самая, что и у меня: не приходит newStopOrders

Попробовал подставить оба варианта _trader.IsAsyncMode = true; и _trader.IsAsyncMode = false; Но всё равно вижу только строку в текстбоксе А вот и мои сделочки:

Moadip
Moadip

Импорт таблицы перестал работать Так а что изменилось то? Сборку новую скачали? Так и пишите тогда, и номер.

Тут, если все правильно понимаю, вы передаете пришедшие сделки в отдельное окно.


private readonly MyTradesWindow _myTradesWindow = new MyTradesWindow();
_trader.NewMyTrades += trades => this.GuiAsync(() => _myTradesWindow.Trades.AddRange(trades));

Логично предположить что где - то это окно потом показывается. В котором должны показываться сделки


_myTradesWindow.Show()

Но вот эти строчки не совсем понятны


foreach (var myTrade in _myTradesWindow.Trades)
{
    var trade = myTrade.Trade;
    tstr = tstr + string.Format("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.\n", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
}

В каком месте этот код обрабатывается? Явно не внутри _myTradesWindow. Т.е. получается что в двух местах что ли информация о сделках показывается? В каком то виде в окне _myTradesWindow и еще в текстбоксе?

Если только в текстбоксе, то проще сделать так


private QuikTrader _trader;
string tstr = "А вот и мои сделочки: \n";

_trader.NewMyTrades += trades => this.GuiAsync(() => 
{
    foreach (var myTrade in trades)
    {
        var trade = myTrade.Trade;
        tstr += string.Format("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.\n", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
    {
    tradestb.Text = tstr;
});

Теперь в чем может быть причина. Проверьте срабатывает ли событие NewMyTrades. Если срабатывает, то посмотрите что находится внутри trades, точнее в одной из сделок var trade = myTrade.Trade; Есть ли в tradeданные.

Творог
Творог
Творог Autor

Ага, я просто конструкцию типа

_trader.NewMyTrades += trades => this.GuiAsync(() => 
{
    foreach (var myTrade in trades)
    {

закомментил, и написал ту, которая выше. Там была проблема, что почему-то выводились только новые сделки при их появлении.

А почему тот блок который я опубликовал нежизнеспособен?

Творог
Творог Autor

И вот ещё вопросец по теме. Допустим я хочу вставить таблицу в форму и для этого вставляю следующий код

        <ListView HorizontalAlignment="Left" Height="339" Margin="435,391,0,0" VerticalAlignment="Top" Width="628" x:Name="TradesDetails" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding ElementName=_myTradesWindow, Path=Trades}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="90" Header="Номер" DisplayMemberBinding="{Binding Path=Trade.Id}" />
                    <GridViewColumn Width="120" Header="Время" DisplayMemberBinding="{Binding Path=Trade.Time}" />
                    <GridViewColumn Width="70" Header="Цена" DisplayMemberBinding="{Binding Path=Trade.Price}" />
                    <GridViewColumn Width="60" Header="Кол-во" DisplayMemberBinding="{Binding Path=Trade.Volume}" />
                    <GridViewColumn Width="100" Header="Инструмент" DisplayMemberBinding="{Binding Path=Trade.Security.Code}" />
                    <GridViewColumn Width="80" Header="Направление" DisplayMemberBinding="{Binding Path=Order.Direction}" />
                    <GridViewColumn Width="90" Header="Заявка" DisplayMemberBinding="{Binding Path=Order.Id}" />
                </GridView>
            </ListView.View>
        </ListView>

Табличка не заполняется (хотя _myTradesWindow.Show() показывает окно со сделками). Я так понимаю, должен где-то "TradesDetails" прописать и что-то ещё сделать?

Moadip
Moadip

Творог: И вот ещё вопросец по теме. Допустим я хочу вставить таблицу в форму и для этого вставляю следующий код

    <ListView HorizontalAlignment="Left" Height="339" Margin="435,391,0,0" VerticalAlignment="Top" Width="628" x:Name="TradesDetails" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding ElementName=_myTradesWindow, Path=Trades}">
        <ListView.View>
            <GridView>
                <GridViewColumn Width="90" Header="Номер" DisplayMemberBinding="{Binding Path=Trade.Id}" />
                <GridViewColumn Width="120" Header="Время" DisplayMemberBinding="{Binding Path=Trade.Time}" />
                <GridViewColumn Width="70" Header="Цена" DisplayMemberBinding="{Binding Path=Trade.Price}" />
                <GridViewColumn Width="60" Header="Кол-во" DisplayMemberBinding="{Binding Path=Trade.Volume}" />
                <GridViewColumn Width="100" Header="Инструмент" DisplayMemberBinding="{Binding Path=Trade.Security.Code}" />
                <GridViewColumn Width="80" Header="Направление" DisplayMemberBinding="{Binding Path=Order.Direction}" />
                <GridViewColumn Width="90" Header="Заявка" DisplayMemberBinding="{Binding Path=Order.Id}" />
            </GridView>
        </ListView.View>
    </ListView>
> 
> Табличка не заполняется (хотя _myTradesWindow.Show() показывает окно со сделками). Я так понимаю, должен где-то "TradesDetails" прописать и что-то ещё сделать?

Зачем изобретать велосипед когда уже есть все готовое? Советую изучить [**Stocksharp.Xaml**](http://stocksharp.com/doc/html/N_StockSharp_Xaml.htm).
Конкретно - [**TradeGrid**](http://stocksharp.com/doc/html/T_StockSharp_Xaml_TradeGrid.htm).
Как работать с этими контролами есть в примерах.
Творог
Творог Autor

Moadip: Зачем изобретать велосипед когда уже есть все готовое? Советую изучить Stocksharp.Xaml. Конкретно - TradeGrid. Как работать с этими контролами есть в примерах.

Сорри, но в хэлпе чисто справочный материал и как им воспользоваться, в данном случае, я не очень понимаю. Указанный код я как раз и забрал у Sample. Можете привести простенький пример как вставить таблицу с коллекцией в свою форму?

Moadip
Moadip

А почему тот блок который я опубликовал нежизнеспособен? Ну почему не жизнеспособен. Если кроме как добавления/вытаскивания во внутреннюю коллекцию Trades объекта _myTradesWindow вы этот объект никак не используете, то это избыточный код.

Если надо куда то складывать пришедшие сделки, сделайте отдельную коллекцию типа List<MyTrade>


private List<MyTrade> _myTradeList = new List<MyTrade>();

Получается следующее(в вашем примере кода)


private QuikTrader _trader;
private List<MyTrade> _myTradeList = new List<MyTrade>();
_trader.NewMyTrades += trades => this.GuiAsync(() => _myTradeList .AddRange(trades));
 
string tstr = "А вот и мои сделочки: \n";
foreach (var myTrade in myTradeList )
{
    var trade = myTrade.Trade;
    tstr = tstr + string.Format("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.\n", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
}
tradestb.Text = tstr;

Творог
VassilSanych
VassilSanych

Moadip: Если надо куда то складывать пришедшие сделки, сделайте отдельную коллекцию типа List<MyTrade> +1 Использовать визуальный контрол в качестве промежуточного хранилища информации - это плохой стиль.

Moadip
Moadip

Xaml


<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xaml="clr-namespace:StockSharp.Xaml;assembly=StockSharp.Xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="5" />
            <RowDefinition Height="237*" />
        </Grid.RowDefinitions>
        
        <Grid  HorizontalAlignment="Left" Name="grid1" VerticalAlignment="Top" Margin="5,5,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="72" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
             
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
             
            <Button Content="Подключиться" Height="23" HorizontalAlignment="Left" Name="btnConnect" VerticalAlignment="Top" Width="100" Click="btnConnect_Click" Grid.Row="1" />
            <Button Content="Экспорт DDE" Height="23" HorizontalAlignment="Left" Name="btnExportDde" VerticalAlignment="Top" Width="100" Click="btnExportDde_Click" IsEnabled="False" Grid.Column="1" Grid.Row="1" />
            <TextBox Height="23" HorizontalAlignment="Left" Name="PathDir" VerticalAlignment="Top" Width="272" Grid.ColumnSpan="3"/>
            <Button Content="..." Name="FindPath" Click="FindPath_Click" HorizontalAlignment="Left" Width="28" Height="23" VerticalAlignment="Top" Grid.Column="3" />
            <Button Content="BuyAtMarket" Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Name="BuyAtMarket" VerticalAlignment="Top" Width="100" Click="BuyAtMarket_Click" IsEnabled="False" />
        </Grid>
        
        <!--Отображение сделок-->
        <xaml:TradeGrid x:Name="TradeGrid" Grid.Row="2"/>
    </Grid>
</Window>

Cs


using System.Linq;
using System.Windows;
using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;

using Ecng.Collections;
using Ecng.Common;
using Ecng.Xaml;

using StockSharp.Algo.Testing;
using StockSharp.BusinessEntities;
using StockSharp.Quik;

namespace Test
{
	public partial class MainWindow
	{
		private RealTimeEmulationTrader<QuikTrader> _quikTrader;

		private Security _security;
		private const string _securityCode = "RIH3";

		private Portfolio _portfolio;
		private const string _portfolioCode = "номер счета";

		public MainWindow()
		{
			InitializeComponent();
		}

		private void FindPath_Click(object sender, RoutedEventArgs e)
		{
			var dlg = new FolderBrowserDialog();

			if (!PathDir.Text.IsEmpty())
				dlg.SelectedPath = PathDir.Text;

			if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				PathDir.Text = dlg.SelectedPath;
			}
		}

		private bool _isConnected;

		private void btnConnect_Click(object sender, RoutedEventArgs e)
		{
			if (!_isConnected)
			{
				if (PathDir.Text.IsEmpty())
					MessageBox.Show(this, "Путь к Quik не выбран");
				else
				{
					if (_quikTrader == null)
					{
						_quikTrader = new RealTimeEmulationTrader<QuikTrader>(new QuikTrader(PathDir.Text));

						_quikTrader.UnderlyingTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MinStepPrice);
						_quikTrader.UnderlyingTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MaxPrice);
						_quikTrader.UnderlyingTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MinPrice);

						_quikTrader.NewSecurities += securities =>
						{
							if (_security.IsNull())
							{
								_security = securities.FirstOrDefault(sec => sec.Code == _securityCode);
								_quikTrader.RegisterMarketDepth(_security);
							}
						};

						_quikTrader.NewPortfolios += portfolios =>
						{
							if (_portfolio.IsNull())
								_portfolio = portfolios.FirstOrDefault(p => p.Name == _portfolioCode);
						};

						// Добавление сделок в TradeGrid
						_quikTrader.NewMyTrades += trades => this.GuiAsync(() => TradeGrid.Trades.AddRange(trades));

						_isConnected = true;
						btnExportDde.IsEnabled = true;
					}

					_quikTrader.Connect();

					_isConnected = true;
					btnConnect.Content = "Отключиться";
				}
			}
			else
			{
				_quikTrader.Disconnect();

				_isConnected = false;
				btnConnect.Content = "Подключиться";
			}
		}

		private void btnExportDde_Click(object sender, RoutedEventArgs e)
		{
			if (_isDdeStarted) StopDde();
			else StartDde();
		}

		private bool _isDdeStarted;

		private void StartDde()
		{
			_quikTrader.StartExport();
			_isDdeStarted = true;
			BuyAtMarket.IsEnabled = true;
		}

		private void StopDde()
		{
			_quikTrader.StopExport();
			_isDdeStarted = false;
			BuyAtMarket.IsEnabled = false;
		}

		protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
		{
			if (_quikTrader != null)
			{
				if (_isDdeStarted) StopDde();
				_quikTrader.Disconnect();
				_quikTrader.Dispose();
			}

			base.OnClosing(e);
		}

		private void BuyAtMarket_Click(object sender, RoutedEventArgs e)
		{
			var order = new Order
			{
				Volume = 1,
				Portfolio = _portfolio,
				Security = _security,
				Direction = OrderDirections.Buy,
				Type = OrderTypes.Limit,
				Price = _security.MaxPrice,
			};

			_quikTrader.RegisterOrder(order);
		}

	}
}

Творог
Творог Autor

Moadip, а если понадобится сделать кастомный набор колонок, эта строка как-то редактируется для вывода только нужной инфы? Ну например, как добавить столбик Ставка РЕПО? <xaml:TradeGrid x:Name="TradeGrid" Grid.Row="2"/>

Moadip
Moadip

Нет, это готовый контрол. Если нужен кастомный набор, то тогда разбираться с примерами. Посмотрел примеры, думал там готовый контрол используется. Но там как раз кастомный набор колонок делается в ListView.

Творог
Творог Autor

А почему моя встроенная в форму табличка (пост #6) компилируется, но не выводится?

VassilSanych
VassilSanych

Творог: А почему моя встроенная в форму табличка (пост #6) компилируется, но не выводится? Во-первых, для проброса изменений в XAML необходимо реализовывать INotifyPropertyChanged или использовать специальные коллекции и назначать их источником данных в коде, во-вторых, если в Binding есть ошибки, WPF об этом не скажет. Просто не будут подтягиваться данные и всё.

Творог
Творог Autor

Честно говоря, не очень понимаю как это реализовывать на практике. С примером было бы легче.

Вот я создаю новую коллекцию

private readonly List<MyTrade> _myTradeList = new List<MyTrade>();

Подписываюсь

_trader.NewMyTrades += trades => this.GuiAsync(() => _myTradeList.AddRange(trades));

Пытаюсь вывести

<ListView ItemsSource="{Binding ElementName=_myTradeList, Path=Trades}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="90" Header="Номер" DisplayMemberBinding="{Binding Path=Trade.Id}" />
                    ......

Что не так?

P.S. Рискнул предположить, что это другой тип коллекции

private readonly ObservableCollection<MyTrade> _myTradeList = new ObservableCollection<MyTrade>();

но это ничего не меняет. По крайней мере в моём коде.

Moadip
Moadip

Рискнул предположить, что это другой тип коллекции Правильно рискнули.🙂 Т.к. ObservableCollectionреализует интерфейс INotifyPropertyChanged.

В примерах как раз данная коллекция и используется:


	public partial class MyTradesWindow
	{
		public MyTradesWindow()
		{
			Trades = new ObservableCollection<MyTrade>();
			InitializeComponent();
		}

		public ObservableCollection<MyTrade> Trades { get; private set; }
	}

Пытаюсь вывести

<ListView ItemsSource=""> <ListView.View> <GridView> <GridViewColumn Width="90" Header="Номер" DisplayMemberBinding="" /> ......

> 
> Что не так?

Вы понимаете смысл написанного?
```csharp
ItemsSource="{Binding ElementName=_myTradeList, Path=Trades}"

Чтобы не выносить себе мозг привязкой в Xaml, делайте привязку в коде. Удалите это ItemsSource="", обзовите как нибудь ListView, например MyTrades


<ListView x:Name="MyTrades">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="90" Header="Номер" DisplayMemberBinding="{Binding Path=Trade.Id}" />
                    ......

В коде, в конструкторе главного окна сделайте привязку.


		public MainWindow()
		{
			InitializeComponent();
			MyTrades.ItemsSource = _myTradeList;
		}

И все будет работать. А на досуге почитайте про привязку данных. Там на этом сайте вообще много чего интересного можно найти, чтобы подтянуть свои знания по C#/WPF

Творог
Творог
Творог Autor

Теперь всё ясно. Как раз строка ItemsSource="" в примере меня и запутала.

Творог
Творог Autor

А как сказать программе нарисовать мне табличку со стаканом?

Делаю так

private ObservableCollection<MarketDepth> _ri = new ObservableCollection<MarketDepth>();
RiQuotes.ItemsSource = _trader.GetMarketDepth("RIH3@RTS"); // тут стринги не принимаются

или как-то так

_trader.MarketDepthsChanged += depths => this.GuiAsync(() => RiQuotes.ItemsSource = _ri.AddRange(depths);

Вывод сюда

        <ListView x:Name="RiQuotes" HorizontalAlignment="Left" Height="567" VerticalAlignment="Top" Width="254" Margin="-4,163,0,0">
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="70" Header="Продажа" DisplayMemberBinding="{Binding Path=Ask}" />
                    <GridViewColumn Width="100" Header="Цена" DisplayMemberBinding="{Binding Path=Price}" />
                    <GridViewColumn Width="70" Header="Покупка" DisplayMemberBinding="{Binding Path=Bid}" />
                </GridView>
            </ListView.View>
        </ListView>

Или так, но это тоже бред какой-то

_trader.MarketDepthsChanged += depths => this.GuiAsync(() => RiQuotes.ItemsSource = _ri.GetMarketDepth((Security)"RIH3@RTS");

В примерах, например, выще не понятно, где в trader.RegisterMarketDepth(lkoh) берётся именно LKOH@EQBR

VassilSanych
VassilSanych
_trader.MarketDepthsChanged += depths => this.GuiAsync(() => RiQuotes.ItemsSource = _ri.AddRange(depths);

Этот код каждый раз меняет привязку. Простого обновления содержимого _ri будет достаточно.

NattyD
NattyD

private const string _ri_code = "RIH3";

.......................................

 _trader.NewSecurities += securities => 
                {
                    var ri = securities.FirstOrDefault(sec => sec.Code == _ri_code);
                    if (ri != null)
                    {
                        _ri = ri;
                        _trader.RegisterMarketDepth(_ri);
                        _trader.RegisterTrades(_ri);
                    }
                };

Творог
Творог Autor

А вот кстати я так и не смог найти описание функции FirstOrDefault. Интуитивно я догадываюсь что она делает, но всё же хотелось бы увидеть её описание.

Alexander
Alexander

Творог: А вот кстати я так и не смог найти описание функции FirstOrDefault. Интуитивно я догадываюсь что она делает, но всё же хотелось бы увидеть её описание.

Гугл в помощь. Он помогает. Часто.

Den
Den

Alexander Mukhanchikov:

Творог: А вот кстати я так и не смог найти описание функции FirstOrDefault. Интуитивно я догадываюсь что она делает, но всё же хотелось бы увидеть её описание.

Гугл в помощь. Он помогает. Часто.

и ведь не поспоришь. супер ответ! +100500 )))

видел тут где-то в топиках ссылку на WPF, там и про LINQ оказалось. продолжу распространять знания: http://www.professorweb.ru/my/LINQ/base/level3/3_5.php

Alexander
Alexander

Мне кажется для всех таких вещей лучший источник - MSDN