Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Объясните мне как делать сабклассинг нескольких контролов в .Net / 10 сообщений из 10, страница 1 из 1
19.09.2013, 07:15
    #38400955
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Глядел сюда:
How to subclass windows in Windows Forms by using Visual Basic .NET or Visual Basic 2005

Если речь идет об Form1 то прямо в ней пишем:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Public Class Form1
  Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Debug.WriteLine(m.ToString())
    Select Case m.Msg
...
    End Select
    ' Forward message to base WndProc.
    MyBase.WndProc(m)
  End Sub
...



А вот если надо например сабклассить Button1, Button2 и кучу чего еще...
В VB6 я тупо делал по своей ф-ции на каждый контрол:

Код: vbnet
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.
'форма
  OldButton1WindowProc = SetWindowLong(Button1.hwnd, GWL_WNDPROC, AddressOf NewButton1WindowProc)
  OldButton2WindowProc = SetWindowLong(Button2.hwnd, GWL_WNDPROC, AddressOf NewButton2WindowProc)

Private Sub Form_Unload(Cancel As Integer)
  'снятие сабклассинга
  SetWindowLong Button1.hwnd, GWL_WNDPROC, OldButton1WindowProc
  SetWindowLong Button2.hwnd, GWL_WNDPROC, OldButton2WindowProc

'модуль
Public OldButton1WindowProc As Long
Public OldButton2WindowProc As Long

Public Function NewButton1WindowProc( _
 ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Select Case Msg
...
  End Select
  NewButton1WindowProc = CallWindowProc(OldButton1WindowProc, hwnd, Msg, wParam, lParam)
End Function

Public Function NewButton2WindowProc( _
 ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Select Case Msg
...
  End Select
  NewButton2WindowProc = CallWindowProc(OldButton2WindowProc, hwnd, Msg, wParam, lParam)
End Function



Здесь (по указанной ссылке) сразу приглянулся вариант:
Subclass Any HWND

Получилось вот чего:
Код: vbnet
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.
'Модуль класса:
Public Class SubclassHWND
  Inherits NativeWindow

  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    ' do whatever custom processing you need for
    ' this message
    Select Case m.HWnd
      Case Form1.Button1.Handle
        Debug.WriteLine("Button1: " & m.ToString())
      Case Form1.Button2.Handle
        Debug.WriteLine("Button2: " & m.ToString())
    End Select
    ' forward message to base WndProc
    MyBase.WndProc(m)
  End Sub
End Class
'Форма:
Public Class Form1
  Dim s1 As SubclassHWND
  Dim s2 As SubclassHWND

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    s1 = New SubclassHWND()
    s1.AssignHandle(Me.Button1.Handle)
    ' Now s1 should be listening to the Button1's messages.

    s2 = New SubclassHWND()
    s2.AssignHandle(Me.Button2.Handle)
    ' Now s2 should be listening to the Button2's messages.
  End Sub

  Private Sub Form1_FormClosed(ByVal sender As Object,
   ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга ??????????
    s1.ReleaseHandle()
    s2.ReleaseHandle()
  End Sub
End Class



Ну т.е. при таком подходе предполагается, что при добавлении сабклассинга нового контрола
будет добавляться
Код: vbnet
1.
2.
3.
4.
  Dim s_NewControl As SubclassHWND
...
  s_NewControl  = New SubclassHWND()
  s_NewControl.AssignHandle(Me.s_NewControl.Handle)


и основной код переработки будет добавляться непосредственно в класс (в единственную ф-цию), а разделение итти через case(hwnd):
Код: vbnet
1.
2.
3.
4.
5.
  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    Select Case m.HWnd
      Case Me.s_NewControl.Handle
        Debug.WriteLine("NewControl: " & m.ToString())
...

Вопрос 1.
Нельзя ли что-то улучшить? Потому как я здесь для себя вырабатываю алгоритм который очевидно буду применять многократно.
С одной стороны я могу создать по классу на каждый контрол, но чувствую так не делают.
С другой стороны чувствую что s1 и s2 уже и так разделены (разные экземпляры класса),
но зачем-то проверяю Me.s_NewControl.Handle, да еще и внутри класса.
Фраза "Now s1 should be listening to the Button1's messages" заставляет задуматься что обработку надо вынести куда-то в другое место и вместо
Case Me.s_NewControl.Handle
использовать
Case s1,s2,s3 (м.б. по типу if (e.name)=s1 then...)
В общем нужно как-то это добить а моя видимо "недоученность" не позволяет мне грамотно дооформить этот код.
Не поможете?

Вопрос 2.
Сабклассинг снимать надо?
И правильно ли я это делаю?

Код: vbnet
1.
2.
3.
4.
  Private Sub Form1_FormClosed(ByVal sender As Object,
   ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга ??????????
    s1.ReleaseHandle()
...
Рейтинг: 0 / 0
19.09.2013, 08:24
    #38400976
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Дмитрий77,

создать наследника для каждого типа контрола - самый прямой и честный путь(в смысле ООП)

если хочется в привычном стиле по функции на каждый контрол - тогда по классу наследнику NativeWindow на каждый контрол(вместо каждой функции) Сахару подсыпать конечно можно - создать единственный экземпляр SubclassHWND на форму (или класс контролов) и в нём на каждый контрол регистрировать делегат обработчик, причём регистрировать сам контрол, а не его hwnd)
в SubclassHWND подписаться на закрытие формы и сделать ReleaseHandle не задумываясь
SubclassHWND можно сделать и поумнее - на самые часто используемые сообщения - создать по виртуальному методу на нужное сообщение в SubclassHWND, а дальнейших наследниках перекывать при необходимости. во втором варианте - регистрировать разные делегаты на разные сообщения,
если параметром делегата сделать не собственно Message, а осмысленные параметры - лямбда может оказаться корошо читаемой

конкретика зависит от количества как типов контролов так и количества экземпляров(регистровать обработчики перечислением имён контролов, типов, задействовать тэги, ограничитьконтейнерами на форме и т д)

P.S. сомнения в правильности выбора инструмента меня не покидают
...
Рейтинг: 0 / 0
19.09.2013, 08:50
    #38400992
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Изопропил,

Я тут еще порыскал, а вот так сойдет? Чтоб шибко не умничать.
По крайней мере я "разделил" более грамотно.
Ничего не упустил?
Код: vbnet
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.
Public Class Form1
  Dim WithEvents s_Button1 As SubclassHWND
  Dim WithEvents s_Button2 As SubclassHWND

  Private Const WM_LBUTTONDOWN As Long = &H201
  Private Const WM_LBUTTONDBLCLK = &H203

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    s_Button1 = New SubclassHWND()
    s_Button1.AssignHandle(Me.Button1.Handle)
    ' Now s1 should be listening to the Button1's messages.

    s_Button2 = New SubclassHWND()
    s_Button2.AssignHandle(Me.Button2.Handle)
    ' Now s2 should be listening to the Button2's messages.
  End Sub

  Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга
    s_Button1.ReleaseHandle()
    s_Button2.ReleaseHandle()
  End Sub

  Private Sub s_Button1_CallBackProc(ByRef m As System.Windows.Forms.Message) Handles s_Button1.CallBackProc
    Debug.WriteLine("button1: " & m.ToString)
    If m.Msg = WM_LBUTTONDOWN Or m.Msg = WM_LBUTTONDBLCLK Then
      m = Nothing '???? 
    End If
  End Sub

  Private Sub s_Button2_CallBackProc(ByRef m As System.Windows.Forms.Message) Handles s_Button2.CallBackProc
    Debug.WriteLine("button2: " & m.ToString)
  End Sub
End Class

Public Class SubclassHWND
  Inherits NativeWindow

  'Event Declaration. This event will be raised when any  
  'Message will be posted to the Control
  Public Event CallBackProc(ByRef m As Message)

  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    RaiseEvent CallBackProc(m) 'then RaiseEvent
    ' forward message to base WndProc
    MyBase.WndProc(m)
  End Sub
End Class



Меня еще смущает в данном случае вариант когда НЕ НАДО обрабатывать msg .
Эквивалентно ли
m = Nothing (выделено в коде)

конструкции
Exit Sub/Exit Function
непосредственно в
Sub WndProc
которая минует
MyBase.WndProc(m)

По крайней мере в приведенном выше тесте первая кнопка не нажимается.
...
Рейтинг: 0 / 0
19.09.2013, 09:25
    #38401019
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Дмитрий77Эквивалентно ли
m = Nothing (выделено в коде)
конструкции
Exit Sub/Exit Function
непосредственно в
Sub WndProc
которая минует
MyBase.WndProc(m)

М.б. лучше
Код: vbnet
1.
 m.Msg = 0


???
...
Рейтинг: 0 / 0
19.09.2013, 10:37
    #38401132
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Дмитрий77,

1)Call base.WndProc for unhandled messages

2)не надо из обработчика бросать исключений.
...
Рейтинг: 0 / 0
19.09.2013, 13:37
    #38401450
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Изопропил,

вот такой говнокод получше видимо будет
Код: 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.
public delegate bool SubWindowFunc(SubWindow h,ref Message m);
    
    public class SubWindow:NativeWindow
    {
        public Control control { get; private set; }
        private SubWindowFunc wf;
        public SubWindow(Control c, SubWindowFunc wf)
        {
            control = c;
            this.wf = wf;
            control.HandleDestroyed += control_HandleDestroyed;
            control.HandleCreated += control_HandleCreated;            
            
        }
        protected override void WndProc(ref Message m)
        {
            if (!wf(this, ref m)) base.WndProc(ref m);
        }

        void control_HandleCreated(object sender, EventArgs e)
        {
            this.AssignHandle(control.Handle);            
        }
       
        void control_HandleDestroyed(object sender, EventArgs e)
        {
            this.ReleaseHandle();
        }
    }

...
Рейтинг: 0 / 0
20.09.2013, 00:13
    #38402235
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
ИзопропилИзопропил,

вот такой говнокод получше видимо будет
Код: 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.
public delegate bool SubWindowFunc(SubWindow h,ref Message m);
    
    public class SubWindow:NativeWindow
    {
        public Control control { get; private set; }
        private SubWindowFunc wf;
        public SubWindow(Control c, SubWindowFunc wf)
        {
            control = c;
            this.wf = wf;
            control.HandleDestroyed += control_HandleDestroyed;
            control.HandleCreated += control_HandleCreated;            
            
        }
        protected override void WndProc(ref Message m)
        {
            if (!wf(this, ref m)) base.WndProc(ref m);
        }

        void control_HandleCreated(object sender, EventArgs e)
        {
            this.AssignHandle(control.Handle);            
        }
       
        void control_HandleDestroyed(object sender, EventArgs e)
        {
            this.ReleaseHandle();
        }
    }

У меня не получается его осознать и перевести на VB.NET, написал бы хотя бы C# было бы проще.

Я так понимаю, ответ на мой вопрос (который единственный меня серьезно беспокоит в моем коде)
Дмитрий77Дмитрий77Эквивалентно ли
m = Nothing (выделено в коде)
конструкции
Exit Sub/Exit Function
непосредственно в
Sub WndProc
которая минует
MyBase.WndProc(m)

М.б. лучше
Код: vbnet
1.
 m.Msg = 0


???
есть:
Изопропил2)не надо из обработчика бросать исключений.

Если я делаю:
Код: vbnet
1.
2.
3.
4.
  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
     RaiseEvent CallBackProc(m)
     MyBase.WndProc(m)
  End Sub


то m передается в CallBackProc ByRef

Соответственно
Код: plaintext
1.
2.
3.
  Private Sub s_Button1_CallBackProc(ByRef m As System.Windows.Forms.Message) Handles s_Button1.CallBackProc
      m = Nothing
  End Sub


приведет к выполнению кода
Код: vbnet
1.
MyBase.WndProc(Nothing)


что наверно не правильно,
потому как правильно вообще ничего не делать (когда не хотим обрабатывать сообщение).


OK, в VB6 есть такое событие:
Код: vbnet
1.
2.
3.
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Cancel = 1 'отмена выгрузки формы
End Sub



Поступая по аналогии...
Как такой вариант? Я думаю, здесь уже не придраться.

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
Public Class SubclassHWND
  Inherits NativeWindow

  Public Event CallBackProc(ByRef m As Message, ByRef Cancel As Boolean)

  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    Dim Cancel As Boolean = False 'по умолчанию обрабатывать сообщение
    RaiseEvent CallBackProc(m, Cancel)
    ' если обрабатываем (cancel=False), то forward message to base WndProc
    If Not Cancel Then MyBase.WndProc(m)
  End Sub
End Class


  Private Sub s_Button1_CallBackProc _
   (ByRef m As System.Windows.Forms.Message, ByRef Cancel As Boolean) Handles s_Button1.CallBackProc
    If m.Msg = WM_LBUTTONDOWN Or m.Msg = WM_LBUTTONDBLCLK Then
      Cancel = True 'не обрабатывать сообщение
    End If
  End Sub
...
Рейтинг: 0 / 0
20.09.2013, 00:56
    #38402254
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Дмитрий77аписал бы хотя бы C# было бы проще.
это был c# :(
...
Рейтинг: 0 / 0
20.09.2013, 01:15
    #38402259
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Изопропилэто был c# :(
Да? Ну извини тогда.
Я на C# не пишу, видимо специфический синтаксис, многие обороты с ходу не понять.
Но в любом случае не сумел понять идеи.
...
Рейтинг: 0 / 0
20.09.2013, 11:40
    #38402578
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Объясните мне как делать сабклассинг нескольких контролов в .Net
Дмитрий77видимо специфический синтаксис
это у бейсика специфический
Код: vbnet
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.
Imports System
Imports System.Windows.Forms

Public Class SubWindow
    Inherits NativeWindow

    Private wf As SubWindowFunc

    Public Property control() As Control

    Public Sub New(c As Control, wf As SubWindowFunc)
        Me.control = c
        Me.wf = wf
        Me.control.HandleDestroyed += New EventHandler(Me.control_HandleDestroyed)
        Me.control.HandleCreated += New EventHandler(Me.control_HandleCreated)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        If Not Me.wf(Me, m) Then
            MyBase.WndProc(m)
        End If
    End Sub

    Private Sub control_HandleCreated(sender As Object, e As EventArgs)
        MyBase.AssignHandle(Me.control.Handle)
    End Sub

    Private Sub control_HandleDestroyed(sender As Object, e As EventArgs)
        Me.ReleaseHandle()
    End Sub
End Class

...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Объясните мне как делать сабклассинг нескольких контролов в .Net / 10 сообщений из 10, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]