Сегодня поговорим о том, как в SketchFlow проекте показать тестовые данные.
Пусть необходим список сотрудников, при клике на конкретном сотруднике открывается более подробная информация.
среда, 25 ноября 2009 г.
понедельник, 23 ноября 2009 г.
Создание окна из потока отличного от потока диспетчера приложения
Возникла задача, в процессе вызова метода из workflow показать форму для ввода дополнительных данных (для тех, кто не в курсе - workflow выполняются в отдельном потоке, и соответственно если метод вызывается из workflow, он тоже выполняется в этом потоке). Приложение написано на WPF. Привычная последовательность действий:
Выполнялось, но форма не появлялась :(
Пришлось пойти на следующее ухищрение:
А вот теперь все работает ;)
public void StartReadFromScala(Guid idWorkflow)
{
WndReadFromScala form = new WndReadFromScala();
form.Show();
}
* This source code was highlighted with Source Code Highlighter.Выполнялось, но форма не появлялась :(
Пришлось пойти на следующее ухищрение:
public void StartReadFromScala(Guid idWorkflow)
{
// Создаем форму для ввода данных, но создаем ее в главном потоке
Application.Current.Dispatcher.Invoke(new NoParamHandler(CreateWndReadFromScala), new object[] { });
}
private void CreateWndReadFromScala()
{
WndReadFromScala form = new WndReadFromScala();
form.Show();
}
* This source code was highlighted with Source Code Highlighter.А вот теперь все работает ;)
вторник, 3 ноября 2009 г.
Олимпиада по многократному решению делемы заключенного
Было принято решение провести олимпиаду по решению многократной дилемы заключенного.
К участию приглашаются все желающие. Дата проведения олимпиады будет объявлена дополнительно. Ориентировочно олимпиада будет проходить 17 декабря 2009 года в 16:00.
Для участия необходимо предоставить dll разработанную на платформе .Net и содержащую класс потомок интерфейса:
Интерфейс добавляется в проект из сборки которую можно скачать здесь.
В процессе проведения соревнования запрещается:
1. Попытка загрузки, рефакторинга, изменения или удаления сборок оппонентов.
2. Запрещается влиять на работу сервера иными средствами кроме возвращения массива из метода MakeStep.
3. Осуществлять сговор участников соревнования.
4. Модифицировать ICompetition.dll или реализовывать интерфейс ICompetition в своих сборках.
Порядок проведения соревнования:
1. Все участники соревнования предоставляют dll удовлетворяющие описанным выше требованиям и запретам.
2. Сервер олимпиады подгружает все зарегистрированные сборки с загрузкой из каждой ОДНОГО класса потомка интерфейса ICompetition.
3. От каждого класса создается объект посредством вызова конструктора по умолчанию.
4. Для каждого созданного объекта вызывается метод SetCount в который передается количество участников соревнований.
5а. В первом туре в метод MakeStep передается null. Метод должен вернуть в виде массива bool-евых значений свое отношение к сборкам противников: true - сотрудничать, false - предавать. Количество значений в массиве должно соответствовать количеству участников полученных классом через метод SetCount.
5б. Во втором и последующих турах (проходит от 30 до 50 туров), в метод MakeStep передается отношение к данному участнику всех оппонентов. Количество значений в массиве соответствует количеству участников полученных классом через метод SetCount. На основе полученных данных необходимо вернуть массив отношения к сборкам противников.
6. Через 5 секунд после вызова соответствующих методов, все методы не закончившие обработку и не вернувшие значение снимаются с соревнований.
7. Если количество туров превысило 30 и сгенерированное случайное число меньше 1/20 то соревнование заканчивается, в противном случае переход в пункт 5б.
Если два участника поставили взаимное true, то каждый из них получает по 7 очков рейтинга. Если два участника поставили взаимное false, то каждый из них получает по 3 очка рейтинга. Если один из участников поставил true в ответ на false другого участника, то первый не получает очки рейтинга, а второй получает 10 очков рейтинга.
Пять программ набравших наибольшее количество баллов рейтинга получают по 5,4,3,2 и 1 очку в зависимости от занятого места.
Соревнования повторяются 3-5 раз. Программа набравшая суммарно максимальное количество очков признается победителем олимпиады.
В качестве приза будет нечто полезное программистам ;)
Удачной олимпиады.
P.s. В случае обнаружения неточностей, ошибок или при наличии предложений писать в комментариях.
К участию приглашаются все желающие. Дата проведения олимпиады будет объявлена дополнительно. Ориентировочно олимпиада будет проходить 17 декабря 2009 года в 16:00.
Для участия необходимо предоставить dll разработанную на платформе .Net и содержащую класс потомок интерфейса:
namespace Competition
{
public interface ICompetition
{
/// <summary>
/// Передает в библиотеку количество участников
/// </summary>
/// <param name="p_count">количество участников</param>
void SetCount(int p_count);
/// <summary>
/// Делает один ход
/// </summary>
/// <param name="p_prevResult">Массив предыдущих ответов соответствующих участников</param>
/// <returns>Массив ответов на текущем шаге</returns>
bool[] MakeStep(bool[] p_prevResult);
}
}
* This source code was highlighted with Source Code Highlighter.Интерфейс добавляется в проект из сборки которую можно скачать здесь.
В процессе проведения соревнования запрещается:
1. Попытка загрузки, рефакторинга, изменения или удаления сборок оппонентов.
2. Запрещается влиять на работу сервера иными средствами кроме возвращения массива из метода MakeStep.
3. Осуществлять сговор участников соревнования.
4. Модифицировать ICompetition.dll или реализовывать интерфейс ICompetition в своих сборках.
Порядок проведения соревнования:
1. Все участники соревнования предоставляют dll удовлетворяющие описанным выше требованиям и запретам.
2. Сервер олимпиады подгружает все зарегистрированные сборки с загрузкой из каждой ОДНОГО класса потомка интерфейса ICompetition.
3. От каждого класса создается объект посредством вызова конструктора по умолчанию.
4. Для каждого созданного объекта вызывается метод SetCount в который передается количество участников соревнований.
5а. В первом туре в метод MakeStep передается null. Метод должен вернуть в виде массива bool-евых значений свое отношение к сборкам противников: true - сотрудничать, false - предавать. Количество значений в массиве должно соответствовать количеству участников полученных классом через метод SetCount.
5б. Во втором и последующих турах (проходит от 30 до 50 туров), в метод MakeStep передается отношение к данному участнику всех оппонентов. Количество значений в массиве соответствует количеству участников полученных классом через метод SetCount. На основе полученных данных необходимо вернуть массив отношения к сборкам противников.
6. Через 5 секунд после вызова соответствующих методов, все методы не закончившие обработку и не вернувшие значение снимаются с соревнований.
7. Если количество туров превысило 30 и сгенерированное случайное число меньше 1/20 то соревнование заканчивается, в противном случае переход в пункт 5б.
Если два участника поставили взаимное true, то каждый из них получает по 7 очков рейтинга. Если два участника поставили взаимное false, то каждый из них получает по 3 очка рейтинга. Если один из участников поставил true в ответ на false другого участника, то первый не получает очки рейтинга, а второй получает 10 очков рейтинга.
Пять программ набравших наибольшее количество баллов рейтинга получают по 5,4,3,2 и 1 очку в зависимости от занятого места.
Соревнования повторяются 3-5 раз. Программа набравшая суммарно максимальное количество очков признается победителем олимпиады.
В качестве приза будет нечто полезное программистам ;)
Удачной олимпиады.
P.s. В случае обнаружения неточностей, ошибок или при наличии предложений писать в комментариях.
суббота, 3 октября 2009 г.
Сервис постоянства в Workflow Foundation
Для одного маленького, но очень интересного проекта решили применить workflow. И сразу необходимо было решить задачу сохранения работающих workflow во внешних хранилищах между запусками клиентских приложений.
В русскоязычном интернете этой проблеме уделено весьма мало внимания... Где можно почитать? Я нашел вот эти работы: на rsdn, gotdotnet и т.д..
Эти статьи либо достаточно поверхностны, либо подразумевают (как последняя) что вы уже все знаете :).
Поэтому давайте попробуем решить поставленную задачу (сохранение workflow во внешнем хранилище) медленно и по шагам.
Итак, для решения данной задачи нам понадобится VS 2008 + MS SQL (версия последнего не особенно принципиальна).
1. Идем сюда и читаем как нам подготовить MS SQL.
2. Создаем простенький workflow на котором будем ставить эксперименты. Для простоты я воспользовался следующим:

Первое состояние стартовое и мы его сразу покидаем. Второе вызывает метод Print из нижеописанного интерфейса и ждет событие из него же. Третье служит для того чтобы сказать что событие успешно получено и обработано.
Обещанный интерфейс:
2. Тестировать будем при помощи формы следующего вида:

Кнопки 2 и 3 создают WorkflowRuntime и все необходимые сервисы, а кроме того кнопка 2 создает экземпляр workflow.
Как видим из метода 2 кнопки Id workflow выводится в textBox.
Кнопка 1 отправляет событие в workflow идентификатор которого берет из поля формы:
А вот кнопка 4 отправляет событие в workflow чей идентификатор берется из textBox-а.
В чем отличие? Если в textBox попадает тот же идентификатор что хранится в поле _instance? смотрим следующий шаг!
3. Запускаем приложение и тестируем работу workflow кликнув на кнопке 2, а затем 1. Поток отрабатывает как и ожидалось, в чем мы можем убедится за счет вызова метода Print например такого содержания:
А теперь самое интересное! Перезапускаем приложение нажимаем на кнопку 2, копируем в буфер обмена значение идентификатора и?..

Перезапускаем приложение!
В новой копии приложения создаем рунтайм (но не workflow) кнопкой 3. Вставляем из буфера в textBox идентификатор. Нажимаем на кнопку 4 и видем в label подтверждение обработки события в workflow.

Или иными словами созданный workflow был успешно сохранен во внешнем хранилище, а при повторном запуске приложения и попытке отправить ему события извлечен из оного. Что собственно говоря и требовалось по условию задачи.
На этом можно бы и закончить, но рекомендую попробовать написать все это самостоятельно ручками ;)
В русскоязычном интернете этой проблеме уделено весьма мало внимания... Где можно почитать? Я нашел вот эти работы: на rsdn, gotdotnet и т.д..
Эти статьи либо достаточно поверхностны, либо подразумевают (как последняя) что вы уже все знаете :).
Поэтому давайте попробуем решить поставленную задачу (сохранение workflow во внешнем хранилище) медленно и по шагам.
Итак, для решения данной задачи нам понадобится VS 2008 + MS SQL (версия последнего не особенно принципиальна).
1. Идем сюда и читаем как нам подготовить MS SQL.
2. Создаем простенький workflow на котором будем ставить эксперименты. Для простоты я воспользовался следующим:

Первое состояние стартовое и мы его сразу покидаем. Второе вызывает метод Print из нижеописанного интерфейса и ждет событие из него же. Третье служит для того чтобы сказать что событие успешно получено и обработано.
Обещанный интерфейс:
[ExternalDataExchangeAttribute()]
public interface IMethodAndEvents
{
event EventHandler<ExternalDataEventArgs> MyEvent;
void PrintText(string p_text);
}
* This source code was highlighted with Source Code Highlighter.2. Тестировать будем при помощи формы следующего вида:

Кнопки 2 и 3 создают WorkflowRuntime и все необходимые сервисы, а кроме того кнопка 2 создает экземпляр workflow.
private void button2_Click(object sender, RoutedEventArgs e)
{
button3_Click(null, null);
_instance = _runtime.CreateWorkflow(typeof(Workflow1));
_instance.Start();
textBox1.Text = _instance.InstanceId.ToString();
}
private void button3_Click(object sender, RoutedEventArgs e)
{
_runtime = new WorkflowRuntime();
// Create the SqlWorkflowPersistenceService.
string connectionString = "Initial Catalog=WorkflowPersistenceStore;Data Source=localhost;Integrated Security=SSPI;";
bool unloadOnIdle = true;
TimeSpan instanceOwnershipDuration = TimeSpan.MaxValue;
TimeSpan loadingInterval = new TimeSpan(0, 2, 0);
SqlWorkflowPersistenceService persistService = new SqlWorkflowPersistenceService(connectionString, unloadOnIdle, instanceOwnershipDuration, loadingInterval);
_runtime.AddService(persistService);
ExternalDataExchangeService externalDataExchangeService = new ExternalDataExchangeService();
_runtime.AddService(externalDataExchangeService);
externalDataExchangeService.AddService(this);
_runtime.StartRuntime();
}
* This source code was highlighted with Source Code Highlighter.Как видим из метода 2 кнопки Id workflow выводится в textBox.
Кнопка 1 отправляет событие в workflow идентификатор которого берет из поля формы:
private void button1_Click(object sender, RoutedEventArgs e)
{
if (MyEvent != null)
{
MyEvent(null, new ExternalDataEventArgs(_instance.InstanceId));
}
}
* This source code was highlighted with Source Code Highlighter.А вот кнопка 4 отправляет событие в workflow чей идентификатор берется из textBox-а.
private void button4_Click(object sender, RoutedEventArgs e)
{
if (MyEvent != null)
{
Guid id = new Guid(textBox1.Text);
MyEvent(null, new ExternalDataEventArgs(id));
}
}
* This source code was highlighted with Source Code Highlighter.В чем отличие? Если в textBox попадает тот же идентификатор что хранится в поле _instance? смотрим следующий шаг!
3. Запускаем приложение и тестируем работу workflow кликнув на кнопке 2, а затем 1. Поток отрабатывает как и ожидалось, в чем мы можем убедится за счет вызова метода Print например такого содержания:
delegate void PrintHandler(string p_text);
public void PrintText(string p_text)
{
// Проверяем совпадает ли поток диспетчера с потоком вызвавшим метод
if (Dispatcher.Thread == Thread.CurrentThread)
{
// Все замечательно :) меняем значение textbox-а
label1.Content = p_text;
}
else
{
// Нет :( все плохо :( перезапускаем метод в потоке диспетчера
Dispatcher.Invoke(new PrintHandler(PrintText), new object[] { p_text });
}
}
* This source code was highlighted with Source Code Highlighter.А теперь самое интересное! Перезапускаем приложение нажимаем на кнопку 2, копируем в буфер обмена значение идентификатора и?..

Перезапускаем приложение!
В новой копии приложения создаем рунтайм (но не workflow) кнопкой 3. Вставляем из буфера в textBox идентификатор. Нажимаем на кнопку 4 и видем в label подтверждение обработки события в workflow.

Или иными словами созданный workflow был успешно сохранен во внешнем хранилище, а при повторном запуске приложения и попытке отправить ему события извлечен из оного. Что собственно говоря и требовалось по условию задачи.
На этом можно бы и закончить, но рекомендую попробовать написать все это самостоятельно ручками ;)
среда, 12 августа 2009 г.
Выполнение кода после изменения текста в ComboBox
Стоит задача после изменения значения в ComboBox, вывести некоторое сообщение пользователю, например, в MessageBox.
В XAML все просто:
Но если в обработчике события тупо вызывать MessageBox.Show возникает проблема: пользователь уже видит MessageBox, а изменение текста еще не произошло :( Что может ввести пользователя в заблуждение.
Решить проблему можно вот таким достаточно извращенным способом:
Но надо будет еще подумать... что то ведь должно быть проще.
В XAML все просто:
<ComboBox SelectionChanged="ComboBox_SelectionChanged" >
<ItemsControl>1</ItemsControl>
<ItemsControl>2</ItemsControl>
<ItemsControl>3</ItemsControl>
<ItemsControl>4</ItemsControl>
</ComboBox>
* This source code was highlighted with Source Code Highlighter.Но если в обработчике события тупо вызывать MessageBox.Show возникает проблема: пользователь уже видит MessageBox, а изменение текста еще не произошло :( Что может ввести пользователя в заблуждение.
Решить проблему можно вот таким достаточно извращенным способом:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DispatcherTimer t = null;
t = new DispatcherTimer(new TimeSpan(1), DispatcherPriority.Background, (s, e1) => { t.Stop(); MessageBox.Show("asdfvasdvc"); }, this.Dispatcher);
t.Start();
}
* This source code was highlighted with Source Code Highlighter.Но надо будет еще подумать... что то ведь должно быть проще.
понедельник, 13 июля 2009 г.
Получение размеров экрана и рабочей области в WPF приложениях
Возникла задача разместить окно приложения в правом нижнем углу.
Можно решить задачу так:
this.Left = SystemParameters.WorkArea.Width - this.Width;
this.Top = SystemParameters.WorkArea.Height - this.Height;
Если применить:
this.Top = SystemParameters.VirtualScreenHeight - this.Height;
то часть окна будет скрыта панелью задач.
Можно решить задачу так:
this.Left = SystemParameters.WorkArea.Width - this.Width;
this.Top = SystemParameters.WorkArea.Height - this.Height;
Если применить:
this.Top = SystemParameters.VirtualScreenHeight - this.Height;
то часть окна будет скрыта панелью задач.
вторник, 23 июня 2009 г.
Путь к каталогу от куда запущено приложение в WPF
Каждый раз не могу вспомнить как же его получать. Запишу сюда, вдруг запомню:
Environment.CurrentDirectory
Environment.CurrentDirectory
Подписаться на:
Сообщения (Atom)