В форме (Windows Form) есть tabControl c несколькими tabPages.
На парочке tabPages есть control (одинаковый тип — скажем comboBox) отвечающий за такой же параметр. Как сделать так чтобы при смене значения в одном менялось значение в другом.
P.s. пож-та, не предлагать вариант в SelectedIndexChanged функции одного менять значение другого.
Здравствуйте, Volopass, Вы писали:
V>В форме (Windows Form) есть tabControl c несколькими tabPages. V>На парочке tabPages есть control (одинаковый тип — скажем comboBox) отвечающий за такой же параметр. Как сделать так чтобы при смене значения в одном менялось значение в другом.
V>P.s. пож-та, не предлагать вариант в SelectedIndexChanged функции одного менять значение другого.
Используйте BindingSource (вроде так называется в win-приложениях). Они умеют отслеживать состояние своих коллекций. И при биндинге двух контролов на один источник при изменении значения в одном будет изменено в другом.
Здравствуйте, mrjeka, Вы писали:
M>Здравствуйте, Volopass, Вы писали:
V>>В форме (Windows Form) есть tabControl c несколькими tabPages. V>>На парочке tabPages есть control (одинаковый тип — скажем comboBox) отвечающий за такой же параметр. Как сделать так чтобы при смене значения в одном менялось значение в другом.
V>>P.s. пож-та, не предлагать вариант в SelectedIndexChanged функции одного менять значение другого.
M>Используйте BindingSource (вроде так называется в win-приложениях). Они умеют отслеживать состояние своих коллекций. И при биндинге двух контролов на один источник при изменении значения в одном будет изменено в другом.
Спасибо.
Этот вариант я знаю, но то как я знаю получается уж слишком ...
Скажем у меня есть 2 textBoxes, которые реально связаны с переменной int iParameter. И хотелось бы прикрутить все это к int.
А тут надо как минимум создать DataTable, в нем Column, да еще одно Row, где и будет храниться этот int. Вот подобный пример, только над DataTable накручивается еще DataSet, а над ним еще и BindingSourсe здесь
Здравствуйте, Volopass, Вы писали:
V>Спасибо. V>Этот вариант я знаю, но то как я знаю получается уж слишком ... V>Скажем у меня есть 2 textBoxes, которые реально связаны с переменной int iParameter. И хотелось бы прикрутить все это к int. V>А тут надо как минимум создать DataTable, в нем Column, да еще одно Row, где и будет храниться этот int. Вот подобный пример, только над DataTable накручивается еще DataSet, а над ним еще и BindingSourсe
"биндиться" можно к любому объекту с публичным свойством, который поддерживает событие ИмяСвойстваChanged, или реализует интерфейс INotifyPropertyChanged.
Здравствуйте, valker, Вы писали:
V>Здравствуйте, Volopass, Вы писали:
V>>Спасибо. V>>Этот вариант я знаю, но то как я знаю получается уж слишком ... V>>Скажем у меня есть 2 textBoxes, которые реально связаны с переменной int iParameter. И хотелось бы прикрутить все это к int. V>>А тут надо как минимум создать DataTable, в нем Column, да еще одно Row, где и будет храниться этот int. Вот подобный пример, только над DataTable накручивается еще DataSet, а над ним еще и BindingSourсe
V>"биндиться" можно к любому объекту с публичным свойством, который поддерживает событие ИмяСвойстваChanged, или реализует интерфейс INotifyPropertyChanged.
спасибо! я сделал это. странно, но примера для простых controls я не смог найти.
Здравствуйте, Volopass, Вы писали:
V>Здравствуйте, valker, Вы писали:
V>>Здравствуйте, Volopass, Вы писали:
V>>>Спасибо. V>>>Этот вариант я знаю, но то как я знаю получается уж слишком ... V>>>Скажем у меня есть 2 textBoxes, которые реально связаны с переменной int iParameter. И хотелось бы прикрутить все это к int. V>>>А тут надо как минимум создать DataTable, в нем Column, да еще одно Row, где и будет храниться этот int. Вот подобный пример, только над DataTable накручивается еще DataSet, а над ним еще и BindingSourсe
V>>"биндиться" можно к любому объекту с публичным свойством, который поддерживает событие ИмяСвойстваChanged, или реализует интерфейс INotifyPropertyChanged.
V>спасибо! я сделал это. странно, но примера для простых controls я не смог найти.
Этот вариант работает, если объект с интерфейсом INotifyPropertyChanged меняется в UI thread.
Если же он меняется в другом thread, то не работает.
Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились.
Здравствуйте, Volopass, Вы писали:
V>Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились. V>Кто что подскажет?
Так как условия вводной постепенно уточняются, а сама вводная всё усложняется, то скоро сюда понабегут гуру и посоветуют тебе смастерить Model-View-Presenter, который хотя и кажется поначалу страшным оверхедом, но все же в подобных задачах является и единственно верным решением, позволяющим не размазывать логику по коду кучи контролов, а сосредоточить обработку событий в одном месте.
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, Volopass, Вы писали:
V>>Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились. V>>Кто что подскажет?
B>Так как условия вводной постепенно уточняются, а сама вводная всё усложняется, то скоро сюда понабегут гуру и посоветуют тебе смастерить Model-View-Presenter, который хотя и кажется поначалу страшным оверхедом, но все же в подобных задачах является и единственно верным решением, позволяющим не размазывать логику по коду кучи контролов, а сосредоточить обработку событий в одном месте.
В том то и дело я не размазываю логику по кучи контролс )))
Есть прибор состоящий из нескольких devices. Каждый device представляет собой объект класс и его на каждое действие выполняется соотвествующей функцией. Зачастую device медленный или оператор может что-нибудь щелкнуть на передней панели и по этому приходится еще иметь и отдельный thread в таком device. Но функции напрямую не вызываются, а применяется функции write & read, первым аргументом которой является имя параметра, по которому ищется функция. Сам параметр является классом и, кроме имени и других членов, имеет List всех контролс, которые присоеденились. Так что пока сделано так — значение параметра меняется и значения поля Text у всех контролс. Так как внутренний thread, то приходится иметь Invoke с дешифрацией.
Но хотелось бы убрать List всех контролс, да и дешифрацию c Invoke ///
Почему это пришлось сделать ... попросили сделать настраиваемую панельку параметров. Скажем для одного важны одни 5 параметров, а для другого другие. И надо было сделать так, чтобы можно было бы выбрать параметры и контролс этого параметра соотвественно менялся. Из-за этого пришлось уже сделать naming convention, подобно такой которая используется в крупных системах. Отсюда вылезли функции write-read.
Также у прибора баывает несколько методов. На каждый метод диалог и многие диалоги имеют контролс, связанный с одним параметром. Кстати в Java таких гиморов со сменой значения контролс не из UI thread нету, хотя есть другие заморочки.
Есть конечно контролс, не привязанные к прибору, но там логика простая ...
V>>Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились. V>>Кто что подскажет?
B>Так как условия вводной постепенно уточняются, а сама вводная всё усложняется, то скоро сюда понабегут гуру и посоветуют тебе смастерить Model-View-Presenter, который хотя и кажется поначалу страшным оверхедом, но все же в подобных задачах является и единственно верным решением, позволяющим не размазывать логику по коду кучи контролов, а сосредоточить обработку событий в одном месте.
Здравствуйте, Mumitroller, Вы писали:
V>>>Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились. V>>>Кто что подскажет?
B>>Так как условия вводной постепенно уточняются, а сама вводная всё усложняется, то скоро сюда понабегут гуру и посоветуют тебе смастерить Model-View-Presenter, который хотя и кажется поначалу страшным оверхедом, но все же в подобных задачах является и единственно верным решением, позволяющим не размазывать логику по коду кучи контролов, а сосредоточить обработку событий в одном месте.
M>А в этом Model-View-Presenter переправлять оповещения об изменениях в UI-поток с помощью http://msdn.microsoft.com/en-us/library/system.componentmodel.asyncoperationmanager.aspx
Здравствуйте, Mumitroller, Вы писали:
M>Здравствуйте, Mumitroller, Вы писали:
V>>>>Также применить control.Invoke() функцию нельзя, так как объект не знает о controls, которые прибандились. V>>>>Кто что подскажет?
B>>>Так как условия вводной постепенно уточняются, а сама вводная всё усложняется, то скоро сюда понабегут гуру и посоветуют тебе смастерить Model-View-Presenter, который хотя и кажется поначалу страшным оверхедом, но все же в подобных задачах является и единственно верным решением, позволяющим не размазывать логику по коду кучи контролов, а сосредоточить обработку событий в одном месте.
M>>А в этом Model-View-Presenter переправлять оповещения об изменениях в UI-поток с помощью http://msdn.microsoft.com/en-us/library/system.componentmodel.asyncoperationmanager.aspx
M>Точнее — переправить с помощью http://msdn.microsoft.com/en-us/library/system.componentmodel.asyncoperation.post.aspx, а саму AsyncOperation получить с помощью вызова AsyncOperationManager.CreateOperation в UI-потоке.
M>Mumitroller
Мне кажется это не совсем то, что я хочу. Честно говоря, я не совсем разобрался в обрывках кода по ссылкам, но нашел пример здесь . Получается, что вывод привязан к конкретному control.
У меня же control binds к объекту NotifyPropertyChangedString класса
//usage
NotifyPropertyChangedString oNotifiableComboboxString = new NotifyPropertyChangedString();
NotifyPropertyChangedString oNotifiableButtonString = new NotifyPropertyChangedString();
NotifyPropertyChangedString oNotifiableRbTextboxString = new NotifyPropertyChangedString();
public Form1()
{
....
comboBox2.DataBindings.Add(new Binding("Text", oNotifiableComboboxString, "StrValue"));
button2.DataBindings.Add(new Binding("Text", oNotifiableButtonString, "StrValue"));
textBox3.DataBindings.Add(new Binding("Text", oNotifiableRbTextboxString, "StrValue"));
...
}
public class NotifyPropertyChangedString : NotifyPropertyChangedBase
{
private string _StrValue;
public string StrValue
{
get { return _StrValue; }
set
{
NotifyPropertyChanged("StrValue", ref _StrValue, ref value);
}
}
}
public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool NotifyPropertyChanged<T>(string propertyName, ref T oldValue, ref T newValue)
{
if (oldValue == null && newValue == null)
{
return false;
}
if ((oldValue == null && newValue != null) || !oldValue.Equals((T)newValue))
{
oldValue = newValue;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
return true;
}
return false;
}
private delegate void vDFUpdateParameter( string StrValue1);
private void vFUpdateParameter(string StrValue1)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(StrValue1));
}
}
}
ключевой момент в том что любой thread должен менять oNotifiableComboboxString.StrValue и тогда все привязанные controls тоже поменяются.
Как тут сделать?
Здравствуйте, Volopass, Вы писали:
V>ключевой момент в том что любой thread должен менять oNotifiableComboboxString.StrValue и тогда все привязанные controls тоже поменяются. V>Как тут сделать?
Так, как говорилось выше — использовать экземпляр AsyncOperation для выполнения действия в нужном (UI) потоке. Применительно к вашему случаю схема может быть следующей:
в UI-потоке с помощью вызова AsyncOperationManager.CreateOperation создается и запоминается в поле класса формы экземпляр AsyncOperation
к классу формы добавляются методы вида
public void SetComboboxString(string value)
{
// эта строка вызывает DoSetComboboxString с аргументом value в UI-потоке
asyncOperation.Post(DoSetComboboxString, value);
}
private void DoSetComboboxString(object data)
{
// этот код выполняется в UI-потоке, поэтому нотификация работает
oNotifiableComboboxString.StrValue = (string)data;
}
другие потоки при необходимости обновить данные делают вызов
form.SetComboboxString("new value");
Но тут есть один подводный камень, о котором следует помнить — может оказаться, что потоки генерируют обновления быстрее, чем UI-поток может их обработать. В результате память начинает забиваться объектами, передаваемыми в UI-поток и очень легко может закончиться. Если такое у вас возможно, то следует подумать об оптимизации количества обновлений и поведении системы, если такая ситуация все-таки случилась. Например, при достижении некоторого порога скорости поступления обновлений можно либо отбрасывать излишние обновления, либо притормаживать потоки, которые их генерируют.
Здравствуйте, Mumitroller, Вы писали:
M>Здравствуйте, Volopass, Вы писали:
V>>ключевой момент в том что любой thread должен менять oNotifiableComboboxString.StrValue и тогда все привязанные controls тоже поменяются. V>>Как тут сделать?
M>Так, как говорилось выше — использовать экземпляр AsyncOperation для выполнения действия в нужном (UI) потоке. Применительно к вашему случаю схема может быть следующей:
M>
M>в UI-потоке с помощью вызова AsyncOperationManager.CreateOperation создается и запоминается в поле класса формы экземпляр AsyncOperation M>к классу формы добавляются методы вида
public void SetComboboxString(string value)
M>{
M> // эта строка вызывает DoSetComboboxString с аргументом value в UI-потоке
M> asyncOperation.Post(DoSetComboboxString, value);
M>}
M>private void DoSetComboboxString(object data)
M>{
M> // этот код выполняется в UI-потоке, поэтому нотификация работает
M> oNotifiableComboboxString.StrValue = (string)data;
M>}
M>другие потоки при необходимости обновить данные делают вызов
form.SetComboboxString("new value");
M>
M>Но тут есть один подводный камень, о котором следует помнить — может оказаться, что потоки генерируют обновления быстрее, чем UI-поток может их обработать. В результате память начинает забиваться объектами, передаваемыми в UI-поток и очень легко может закончиться. Если такое у вас возможно, то следует подумать об оптимизации количества обновлений и поведении системы, если такая ситуация все-таки случилась. Например, при достижении некоторого порога скорости поступления обновлений можно либо отбрасывать излишние обновления, либо притормаживать потоки, которые их генерируют.
M>Mumitroller
Спасибо. Этот вариант понятен.
Но тут 2 проблемы.
1. Хочется, чтобы DoSetComboboxString() была одна на все про все. Поэтому UI ничего не знает о конкретном oNotifiableComboboxString. Это наверное можно обойти использовав
struct SNotifiableData{
NotifyPropertyChangedString oNotifyPropertyChangedString;
string StrValue;
}
...
private void DoSetComboboxString(object data)
{
// этот код выполняется в UI-потоке, поэтому нотификация работает
SNotifiableData oSNotifiableData = (SNotifiableData) object;
oSNotifiableData.oNotifyPropertyChangedString.StrValue = oSNotifiableData.StrValue;
}
2. Thread, а точнее класс, в котором он определен, ничего не знает о Form. Поэтому как вызвать вот такое form.SetComboboxString(***) непонятно
Можно конечно притащить form в класс, но очень бы не хотелось ...
Здравствуйте, Volopass, Вы писали:
V>Спасибо. Этот вариант понятен. V>Но тут 2 проблемы.
Своим примером я лишь продемонстрировал способ, которым можно воспользоваться, когда надо выполнить некоторое действие в заранее известном потоке. Поэтому в примере нет ничего не относящегося к вопросу.
V>1. Хочется, чтобы DoSetComboboxString() была одна на все про все. Поэтому UI ничего не знает о конкретном oNotifiableComboboxString. Это наверное можно обойти использовав
V>
V>struct SNotifiableData{
V> NotifyPropertyChangedString oNotifyPropertyChangedString;
V> string StrValue;
V>}
V>...
V>private void DoSetComboboxString(object data)
V>{
V> // этот код выполняется в UI-потоке, поэтому нотификация работает
V> SNotifiableData oSNotifiableData = (SNotifiableData) object;
V> oSNotifiableData.oNotifyPropertyChangedString.StrValue = oSNotifiableData.StrValue;
V>}
V>
Вполне себе вариант. Можно еще попробовать использовать лямбду вместо DoSetComboboxString — возможно, это будет читабельнее.
V>2. Thread, а точнее класс, в котором он определен, ничего не знает о Form. Поэтому как вызвать вот такое form.SetComboboxString(***) непонятно V>Можно конечно притащить form в класс, но очень бы не хотелось ...
Так или иначе какой-то канал для передачи данных между классом и формой организовывать придется. И каким он будет — это вопрос архитектуры, а давать советы по архитектуре я не возьмусь.
Mumitroller
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[13]: как "связать" controls
От:
Аноним
Дата:
25.03.11 06:22
Оценка:
Здравствуйте, Mumitroller, Вы писали:
M>Здравствуйте, Volopass, Вы писали:
V>>Спасибо. Этот вариант понятен. V>>Но тут 2 проблемы.
M>Своим примером я лишь продемонстрировал способ, которым можно воспользоваться, когда надо выполнить некоторое действие в заранее известном потоке. Поэтому в примере нет ничего не относящегося к вопросу.
V>>1. Хочется, чтобы DoSetComboboxString() была одна на все про все. Поэтому UI ничего не знает о конкретном oNotifiableComboboxString. Это наверное можно обойти использовав
V>>
V>>struct SNotifiableData{
V>> NotifyPropertyChangedString oNotifyPropertyChangedString;
V>> string StrValue;
V>>}
V>>...
V>>private void DoSetComboboxString(object data)
V>>{
V>> // этот код выполняется в UI-потоке, поэтому нотификация работает
V>> SNotifiableData oSNotifiableData = (SNotifiableData) object;
V>> oSNotifiableData.oNotifyPropertyChangedString.StrValue = oSNotifiableData.StrValue;
V>>}
V>>
M>Вполне себе вариант. Можно еще попробовать использовать лямбду вместо DoSetComboboxString — возможно, это будет читабельнее.
V>>2. Thread, а точнее класс, в котором он определен, ничего не знает о Form. Поэтому как вызвать вот такое form.SetComboboxString(***) непонятно V>>Можно конечно притащить form в класс, но очень бы не хотелось ...
M>Так или иначе какой-то канал для передачи данных между классом и формой организовывать придется. И каким он будет — это вопрос архитектуры, а давать советы по архитектуре я не возьмусь.
M>Mumitroller
вообщем пришлось мне почитать ... вот тут здесь описано как легко сделать через SynchronizationContext.
есть еще пара вариантов это сделать один из которых асинхронный.
Здравствуйте, <Anonymous>, Вы писали:
A>вообщем пришлось мне почитать ... вот тут здесь описано как легко сделать через SynchronizationContext. A>есть еще пара вариантов это сделать один из которых асинхронный.
Вроде читал где-то, что AsyncOperation — это обертка над SynchronizationContext. Но я не заглядывал внутрь, может быть это мне только показалось.
Здравствуйте, Mumitroller, Вы писали:
M>Здравствуйте, <Anonymous>, Вы писали:
A>>вообщем пришлось мне почитать ... вот тут здесь описано как легко сделать через SynchronizationContext. A>>есть еще пара вариантов это сделать один из которых асинхронный.
M>Вроде читал где-то, что AsyncOperation — это обертка над SynchronizationContext. Но я не заглядывал внутрь, может быть это мне только показалось.
M>Mumitroller
наоборот. SynchronizationContext должна быть обертка над AsyncOperation