Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Обращения к контролам формы из другого класса

Всем привет!
Хочу узнать мнение программистов с опытом, по поводу следующего вопроса
Каким образом лучше обращаться к контролам формы из другого класса?
Чуть размышлений :
Понимаю, что сделать контрол публичным - это нарушит ООП
Вариант сделать в классе формы свойство с приватным сэттером, которое будет возвращать ссылку на нужный контрол? Или передавать контрол при создании класса, через агрегацию?
А если этих контролов много?

Вопрос возник с необходимостью отделить некую часть, отдельную логику, которая напрямую взаимродействует с большим количеством контролов на форме
Буду благодарен за советы!
Ответ: LightZ, да, категорически не рекомендуется. Почитайте вот это , там хорошо написано по этому поводу.
Вопрос: Обновление контрола формы из отдельного потока не класса формы

Привет.
Нужно подпнуть, что-то я не догоняю...
Запускаю по клику отдельный поток для вычислений, в этом потоке есть обращение к другому классу, т.е. вычисления уже улетели из класса исходной формы, и, стало быть, через делегатов не могу обновить так Me.txtText=....Поэтому обращаюсь через имя формы frmTwo.txtText=....Инвок выполняется, данные передаются (проверил через мессагу), но контролы не обновляются ((

Добавлено через 38 минут
При этом когда это все выполняется в классе формы - все обновляется.
Ответ: А...ясно, благодарю за наводку!

Добавлено через 1 час 18 минут
Все заработало, благодарю! Достаточно было контрол передать

Добавлено через 3 минуты
Еще вопрос - прочитал про разделение ГПИ и модели...но не понял - там постоянно упоминается обработка в модели данных, а не в контролах...Что там понимается под обработкой в контролах - работа в классе контрола?
Вопрос: Изменение координат 400 контролов - форма лагает

При изменении координат (около 250 -500 объектов) тормоза и не очень красивые эффекты.
Подскажите пожалуйста, можно как то это "вылечить" ?

Списки заполняются динамически в зависимости от необходимого количества полей.

Выглядит на форме так (это калькулятор под некоторые расчеты)
|1|textbox|textbox|textbox|textbox|textbox|textbox|button add|button del|
|2|textbox|textbox|textbox|textbox|textbox|textbox|button add|button del|

....
|50|textbox|textbox|textbox|textbox|textbox|textbox|button add|button del|

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

Цикл пересчета координат.
Код C#
1
2
3
4
5
6
7
8
9
10
11
12
13
Списки (под каждый столбец) List<TextBox> a1_array = new List<TextBox>(0);
 
while (i < count)
                {
                   a1_array[i].Location = new Point(a1array[0].Location.X, a);
                   a2_array[i].Location = new Point(a2array[0].Location.X, a);
                   a3_array[i].Location = new Point(a3array[0].Location.X, a);
                   a4_array[i].Location = new Point(a4array[0].Location.X, a);
                   a5_array[i].Location = new Point(a5array[0].Location.X, a);
                   a += 22;
                   i++;
                }
this.Refresh();
Ответ:
Сообщение от Askfor
Если надо больше то нужно искать другие варианты.
Делать из грида. У него нет реалигна элементов. Не знаю есть ли в WindowsForms возможность вставлять свои контролы в ячейки грида, но под VCL к примеру возможности нет, но есть возможность написать компонент на базе грида в котором эта возможность будет.
Еще вариант - искать флаг отключения имплементации изменений формой, на время перетасовки контролов, чтобы она выполняла пересчет координат только после того как все координаты расставлены.
Вопрос: Методы Controls.Clear и Controls.Remove активируют форму.

При вызове методов Control.ControlCollection.Clear() и Control.ControlCollection.Remove(Control control) при динамическом обновлении элементов типа Control по таймеру форма активируется и выводится наверх. Вызов метода типа this.Activated += new EventHandler(Form_Activated); с активацией нужной формы и выводом ее наверх может решить проблему, но можно ли сделать проще без отслеживания активации формы и без WinAPI? Если выполнить для формы this.Enabled = false; а затем после обновления элементов this.Enabled = true; активация и вывод формы наверх не происходит, но элементы на форме обновляются медленно. Есть ли простой и быстро работающий способ запретить активацию формы при вызове указанных методов?
Ответ:
Активация формы происходила, если очистить панель, удалить элементы на ней или удалить саму панель. Похоже, что решил вопрос с помощью метода WinAPI EnableWindow - при этом обновление работает с нормальной скоростью, в отличие от изменения свойства this.Enabled. Если временно отключить Enabled для окна формы, обновляет содержимое формы без ее активации.
Вопрос: Обращение к контролу из потока

Помогите пожалуйста разобраться с обращением к контролам из потока. Приведенный под спойлером для примера код взят помоему с msdn и работает
Код vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Imports System.Threading
 
Public Class Form1
    Dim trd As Thread
 
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        start_thread()
    End Sub
 
    Function start_thread()
        trd = New Thread(AddressOf ThreadTask)
        trd.IsBackground = True
        trd.Start()
    End Function
 
    Public Sub ThreadTask()
        Dim stp As Integer
        Dim newval As Integer
        Dim rnd As New Random()
        Do
            stp = Me.ProgressBar1.Step * rnd.Next(-1, 2)
            newval = Me.ProgressBar1.Value + stp
            If newval > Me.ProgressBar1.Maximum Then
                newval = Me.ProgressBar1.Maximum
            ElseIf newval < Me.ProgressBar1.Minimum Then
                newval = Me.ProgressBar1.Minimum
            End If
            Me.ThreadProgressChanged(newval)
            Thread.Sleep(100)
        Loop
    End Sub
 
    Public Delegate Sub SubWithParam(ByVal param As Integer)
    Public Sub ThreadProgressChanged(ByVal param As Integer)
        Dim temp As Boolean = Me.ProgressBar1.InvokeRequired
        Dim temp2 As Boolean = Me.ProgressBar1.IsHandleCreated
        If temp Then
            Me.ProgressBar1.BeginInvoke(New SubWithParam(AddressOf ThreadProgressChanged), param)
        Else
            Me.ProgressBar1.Value = param
        End If
    End Sub
End Class
Но если в потоке попробовать выполнить метод из другого класса, и в нем попробовать обратиться к контролам то ничего не получается. Я конечно только начинающий, но я уже потратил три вечера на поиск примера или хотя бы объяснения. Подскажите почему вот так не работает:
Код vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
'код файла Form1.vb
 
Public Class Form1
    Dim work As worker
 
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        work = New worker
        work.start_thread()
    End Sub
End Class
'#########
'код worker.vb
 
Imports System.Threading
 
Public Class worker
    Dim trd As Thread
 
    Function start_thread()
        trd = New Thread(AddressOf ThreadTask)
        trd.IsBackground = True
        trd.Start()
    End Function
 
    Public Sub ThreadTask()
        Dim stp As Integer
        Dim newval As Integer
        Dim rnd As New Random()
        Dim work As New worker
 
        Do
            stp = Form1.ProgressBar1.Step * rnd.Next(-1, 2)
            newval = Form1.ProgressBar1.Value + stp
            If newval > Form1.ProgressBar1.Maximum Then
                newval = Form1.ProgressBar1.Maximum
            ElseIf newval < Form1.ProgressBar1.Minimum Then
                newval = Form1.ProgressBar1.Minimum
            End If
            Me.ThreadProgressChanged(newval)
            Thread.Sleep(100)
        Loop
    End Sub
 
    Public Delegate Sub SubWithParam(ByVal param As Integer)
    Public Sub ThreadProgressChanged(ByVal param As Integer)
        Dim temp As Boolean = Form1.ProgressBar1.InvokeRequired
        Dim temp2 As Boolean = Form1.ProgressBar1.IsHandleCreated
        If temp Then
            Form1.ProgressBar1.BeginInvoke(New SubWithParam(AddressOf ThreadProgressChanged), param)
        Else
            Form1.ProgressBar1.Value = param
        End If
    End Sub
End Class
свойства InvokeRequired и IsHandleCreated в последнем случае всегда возвращают false, и я не смог найти информации почему, ведь форма то не умерла и контролы с нее никуда не делись.
З.Ы. я пробовал создавать поток в классе формы а в качестве параметра в конструктор класса Thread передавать метод из созданного экземпляра класса worker, и делегаты с методами, которые обращаются к контролам формы реализовывать в классе формы - результат один - если метод который выполняется в потоке не принадлежит классу формы, обратиться не получается.
Ответ: Вот это
Код vb.net
1
newval = Form1.ProgressBar1.Value + stp
тоже обращение из потока. Так делать не стоит.
Сообщение от kraew2006
но я не могу понять почему я должен объявлять переменную с типом Form1, но не могу без типа или с типом Object (точнее не могу потом обратится элементам формы)?
Можно и как Object. Только все методы, что доступны, будут от класса Object, а не формы.
Можно Object привести к нужному классу перед использованием. Чем вам мешает нормальное объявление?
Вопрос: Очистить все контролы формы из модуля

Собственно сабж.

Есть главная форма с кнопками, открывающими 2 формы + эти самые 2 формы, на них контролы (TextBox, ListBox).

При закрытии любой из второстепенных форм, на которых контролы, вызывается такая процедура:

Код vb.net
1
UnSet_Data(Me)
Эта процедура находится в модуле.
При её вызове (при закрытии какой-то второстепенной формы), в зависимости от "переданного" в параметре указателя на форму, она должна очищать все контролы, которые есть на переданной форме.

Я попробовал сотворить нечто подобное, но оно не сработало

Вот код процедуры в модуле:


Код vb.net
1
2
3
4
5
6
7
8
9
10
11
12
13
Module Module1
 
...
 
Public Sub UnSet_Data(ByRef F As Form)
    For Each F_Control As Control In F.Controls
        If TypeOf F.Controls(F_Control.Name) Is TextBox Then F.Controls(F_Control.Name).Text = "-"
    Next F_Control
End Sub
 
...
 
End Module

Помогите решить задачу...

+ нужно еще, чтобы все ListBox тоже очищались!
Ответ:
Код vb.net
1
2
3
4
5
6
7
8
9
10
 For Each F_Control As Control In F.Controls
            Dim _control As Object = F.Controls(F_Control.Name)
            If TypeOf _control Is TextBox Then
                _control.Text = "-"
            ElseIf TypeOf _control Is ListBox Then
                _control.items.clear()
            ElseIf TypeOf _control Is ComboBox Then
                _control.selectedindex = -1
            End If
        Next F_Control
Добавлено через 16 минут
или так
Код vb.net
1
2
3
4
5
6
7
8
9
 For Each F_Control As Object In F.Controls
            If TypeOf F.Controls(F_Control.Name) Is TextBox Then
                F.Controls(F_Control.Name).Text = "-"
            ElseIf TypeOf F.Controls(F_Control.Name) Is ListBox Then
                F.Controls(F_Control.Name).items.clear()
            ElseIf TypeOf F.Controls(F_Control.Name) Is ComboBox Then
                F.Controls(F_Control.Name).selectedindex = -1
            End If
        Next F_Control
Вопрос: стиль WS_EX_LAYERED и отображение контролов формы

Доброго времени суток.
Нужно окно произвольной формы по заданному изображению с png файла. Использую отрисовку контура окна по альфа-каналу исходного изображения. Все работает, только вот контролы не отображаются Может кто знает как это исправить. Ниже привожу код, который нашел в паутине, но переделанный под себя:
Код C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
private void Form1_Load(object sender, EventArgs e)
        {
            //Исходное изображение
            FBackground = new Bitmap(Image.FromFile(".\\2.png"));
            //Размер окна по размеру картинки
            this.Width = FBackground.Width;
            this.Height = FBackground.Height;
            // Устанавливаем стиль WS_EX_LAYERED для нашей формы
            long style = CreateParams.ExStyle;
            style |= Windows.WS_EX_LAYERED;            
            Windows.SetWindowLong(this.Handle, Windows.GWL_EXSTYLE, (IntPtr)style);
            //Пустой битмэп и связаный с ним объект Graphics
            FBitmap = new Bitmap(this.Width, this.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            FGraphics = Graphics.FromImage(FBitmap);
            FGraphics.PageUnit = GraphicsUnit.Pixel;                        
            //Рисуем исходное изображение в виртуальном Graphics
            FGraphics.DrawImage(FBackground, 0, 0);
            //Далее самое интресное
            UpdateLayeredForm();
        }
 private void UpdateLayeredForm()
        {
            //Графический контекст окна (формы)
            IntPtr SrcDC = Windows.GetDC(this.Handle);
            //Виртуальный контекст по образцу контекста формы
            IntPtr DestDC = Windows.CreateCompatibleDC(SrcDC);
            //Хендл картинки в памяти
            IntPtr BitmapHandle = FBitmap.GetHbitmap(Color.FromArgb(0));
            //Применяем графические атрибуты битмапа для виртуального графического контекста
            IntPtr PrevBitmap = Windows.SelectObject(DestDC, BitmapHandle);
            Windows.Size Size = new Windows.Size()
            {
                X = Width,
                Y = Height
            };
 
            Windows.Point S = new Windows.Point()
            {
                X = 0,
                Y = 0
            };
 
            Windows.Point P = new Windows.Point()
            {
                X = 0,
                Y = 0
            };
            // Струкиура BlendFunction 
            Windows.BlendFunction BlendFunc = new Windows.BlendFunction()
            {
                BlendOp = Windows.AC_SRC_OVER,
                BlendFlags = 0x00,
                AlphaFormat = Windows.AC_SRC_ALPHA, //Прозрачность формы будет задаваться альфа каналом пиксела изображения (или как-то так:))
                SourceConstantAlpha = FOpacity 
            };
           //Собственно применяем, то что нагородили ранее...
            Windows.UpdateLayeredWindow(this.Handle, SrcDC, ref P, ref Size, DestDC, ref S, 0, ref BlendFunc, Windows.ULW_ALPHA);
            //Востанавливаем прежние графические атрибуты
            Windows.SelectObject(SrcDC, PrevBitmap);
            //Освобождаем память
            Windows.DeleteObject(BitmapHandle);            
            Windows.DeleteDC(DestDC);
            Windows.DeleteDC(SrcDC);
        }
 
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            FGraphics.DrawImage(FBackground, 0, 0);
            UpdateLayeredForm();           
           
        }
Ответ: Спасибо. Приблизительно я так и думал.
Вопрос: Изменение контролов формы из стороннего класса

Добрый день!
Помогите с пониманием решения задачи?

Суть:
1. Есть public static class SomeClass;
2. Есть форма public partial class MainForm : Form;
3. В статичный класс извне поступают данные, обрабатываются внутри цикла.

Задача:
1. Нужно передать из цикла данные в форму с внесением изменений в textBox, label, checkBox;
2. Обновление textBox, label, checkBox должно происходить по мере поступления данных до завершения работы цикла.

Если обращаться к методу формы из статического класса, то использовать "this", согласно MSDN - нельзя, но как тогда обратиться к классу формы без ссылки на объект, метод которого выполняется? А без ссылки не будут меняться контролы textBox, label, checkBox. Замкнутый круг какой-то

Помогите понять, как это работает?
Ответ: Благодарю! Думаю, это ответ на мой вопрос. Буду разбираться, что тут написано.

Добавлено через 27 минут
Работает!!!
В эту сторону совсем не думал.. Премного благодарен!
Вопрос: Перебор контролов формы

Доброго времени суток всем,
столкнулся с тривиальной задачей:
перебрать все контролы на форме включая дочерние,
но почему то элементы меню, ToolStripButton и т.п. как дочерние не воспринимаются,
кто нибуть сталкивался?
Ответ: Все можно сделать проще.
C#
1
TextBox tbx = this.Controls.Find("textBox1", true).FirstOrDefault() as TextBox;
Вопрос: Обновление контрола формы из другого потока

Visual Studio Ultimate 2013(первая версия) позволяет обновить элемент управления формы
из другого потока непосредственно. (т. е. без использования метода Invoke(Delegate...).

Можно ли настройками в Visual Studio запретить это обновление?
(т. е. чтобы контрол обновлялся из другого потока только используя метод Invoke...)
Ответ: Возможно, если убрать наследование!