DOBON.NETプログラミング道掲示板

[ 最新記事及び返信フォームをトピックトップへ ]

■34016 / inTopicNo.1)  フォームコントロールへのDataBindingsでプロパティが相互反映されない
  
□投稿者/ やむ 一般人(1回)-(2018/11/05(Mon) 13:38:52)
  • アイコン環境/言語:[Win10 VB.NET .NET Framework4.6.1] 
    分類:[.NET] 

    お世話になっております。
    
    DataBindingsで自作クラスのプロパティとフォームのコントロールを紐づけ、
    PropertyChangedでプロパティの変更を拾い、処理を行おうとしています。
    customer_code テキストボックス の値の変更を拾い、customer_name テキストボックスに
    値をセットすることはできるのですが、桁を補完した customer_code がテキストボックスに反映されません。
    原因と対処法をお教えください。
    よろしくお願いいたします。
    
    以下、ソース(一部抜粋)
    
    Public Class ModelBase
        Implements INotifyPropertyChanged
    
        Protected Overridable Sub OnPropertyChanged(<CallerMemberName()> Optional propertyName As String = Nothing)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    End Class
    
    Public Class Customers
        Inherits ModelBase
    
        Private _customer_code As String
        Public Property customer_code As String
            Get
                Return _customer_code
            End Get
            Set(value As String)
                If Not value = _customer_code Then
                    _customer_code = value
                    OnPropertyChanged()
                End If
            End Set
        End Property
        Public Property customer_name As String
    End Class
    
    Public Class Form1
        Private WithEvents head As Customers
    
        Sub New()
            InitializeComponent()
    
            head = New Customers
            AddHandler head.PropertyChanged, AddressOf HeaderProperties_ValueChanged
            SetupHeaderControls()
        End Sub
    
        Private Sub SetupHeaderControls()
            For Each prop In head.GetType.GetProperties
                Select Case prop.Name
                    Case "is_output", "created_at", "created_name", "updated_at", "updated_name", "order_date"
                        '何もしない
                    Case Else
                        '同名のコントロールを取得
                        Dim con As Control = common.FindControl(Me, prop.Name)
                        'プロパティとコントロールの紐づけ
                        DataBindingsToControls(con, head, prop.Name)
                End Select
            Next
        End Sub
    
        Private Sub DataBindingsToControls(con As Control, src As Object, srcProperty As String)
            Dim prop As String = ""
            Select Case True
                Case TypeOf con Is TextBox, TypeOf con Is Label
                    con.DataBindings.Add("Text", src, srcProperty, True, DataSourceUpdateMode.OnValidation)
                Case TypeOf con Is ComboBox
                    con.DataBindings.Add("SelectedValue", src, srcProperty, True, DataSourceUpdateMode.OnPropertyChanged)
                Case TypeOf con Is CheckBox, TypeOf con Is RadioButton
                    con.DataBindings.Add("Checked", src, srcProperty, True, DataSourceUpdateMode.Never)
                Case TypeOf con Is DateTimePicker
                    con.DataBindings.Add("Value", src, srcProperty, True, DataSourceUpdateMode.OnValidation)
            End Select
        End Sub
    
        Private Sub HeaderProperties_ValueChanged(sender As Object, e As PropertyChangedEventArgs) Handles head.PropertyChanged
            If e.PropertyName = "customer_code" Then
                If Not head.customer_code = "" Then
                    Dim masterUtil As New MasterUtil
                    '入力値の前を"0"で埋める
                    head.customer_code = common.SetPrefix(head.customer_code, 6, "0")  '←プロパティの値は桁補完できているが、テキストボックスに反映されない
                    head.customer_name = masterUtil.GetCustomerName(head.customer_code)
                End If
            End If
        End Sub
    End Class

マルチポストを報告
違反を報告
引用返信 削除キー/
■34017 / inTopicNo.2)  Re[1]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ 魔界の仮面弁士 大御所(1158回)-(2018/11/05(Mon) 15:46:54)
  • アイコンNo34016に返信(やむさんの記事)
    > head.customer_code = common.SetPrefix(head.customer_code, 6, "0")
    とりあえず
     head.customer_code = head.customer_code.Trim().PadLeft(6, "0"c)
    で代用してみました。


    > 値をセットすることはできるのですが、桁を補完した customer_code がテキストボックスに反映されません。

    ValueChanged イベント中で、Value を再編集しているためではないでしょうか。

    .DataBindings.Add() したインスタンス (As Binding)を保持しておき、
    ValueChanged 後に Binding クラスの ReadValue メソッドを呼び直せば、
    Me.customer_code.Text に桁補完結果が反映されるようです。
違反を報告
引用返信 削除キー/
■34019 / inTopicNo.3)  Re[2]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ 魔界の仮面弁士 大御所(1160回)-(2018/11/05(Mon) 17:10:50)
  • アイコンNo34017に追記(魔界の仮面弁士の記事)
    > .DataBindings.Add() したインスタンス (As Binding)を保持しておき、
    > ValueChanged 後に Binding クラスの ReadValue メソッドを呼び直せば、
    > Me.customer_code.Text に桁補完結果が反映されるようです。

    別案。
    BindingComplete イベントを使ってみました。



    Private Sub DataBindingsToControls(con As Control, src As Object, srcProperty As String)
      Dim prop As String = ""
      Select Case True
        Case TypeOf con Is TextBoxBase

          ' 双方向にするため、BindingComplete イベント内で ReadValue メソッドを呼び出す
          AddHandler con.DataBindings.Add("Text", src, srcProperty, True, DataSourceUpdateMode.OnValidation).BindingComplete, _
            Sub(sender As Object, e As BindingCompleteEventArgs)
              e.Binding.ReadValue()
            End Sub

        Case TypeOf con Is Label
          con.DataBindings.Add("Text", src, srcProperty, True, DataSourceUpdateMode.OnValidation)
        Case TypeOf con Is ComboBox
          DataBindings.Add("SelectedValue", src, srcProperty, True, DataSourceUpdateMode.OnPropertyChanged)
        Case TypeOf con Is CheckBox, TypeOf con Is RadioButton
          DataBindings.Add("Checked", src, srcProperty, True, DataSourceUpdateMode.Never)
        Case TypeOf con Is DateTimePicker
          DataBindings.Add("Value", src, srcProperty, True, DataSourceUpdateMode.OnValidation)
      End Select
    End Sub

    #Region "Common.FindControl の仕様が分からないけど、こんな感じだろうか"
    Private Function FindControl(container As Control, name As String) As Control
      Return FindControls(container).FirstOrDefault(Function(c) c.Name = name)
    End Function
    Private Function FindControls(container As Control) As IEnumerable(Of Control)
      Dim controls = container.Controls.Cast(Of Control)()
      Dim children = controls.Select(AddressOf FindControls)
      Return controls.Concat(children.SelectMany(Function(c) c))
    End Function
    #End Region



    上記では、無条件で BindingComplete イベントにアタッチしていますが、
    汎用的にするならば、双方向バインドと片方向バインドを切り替えられるように
    Customers の customer_code プロパティにカスタム属性を付与しておくとか、
    あるいは、ReadValue を抑制するための コールバックイベントを用意するなど
    しておくという手もあるかも。
違反を報告
引用返信 削除キー/
■34020 / inTopicNo.4)  Re[3]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ やむ 一般人(2回)-(2018/11/05(Mon) 17:58:05)
  • アイコンNo34019に返信(魔界の仮面弁士さんの記事)

    > 別案。
    > BindingComplete イベントを使ってみました。

    魔界の仮面弁士さん
    参考ソースまでありがとうございます。
    まだ実際に動かしたりできておりませんが、取り急ぎお礼まで。
違反を報告
引用返信 削除キー/
■34021 / inTopicNo.5)  Re[4]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ やむ 一般人(3回)-(2018/11/06(Tue) 09:51:01)
  • アイコン>>魔界の仮面弁士さん
    参考ソースありがとうございました。
    問題は解決できたので、解決済みとしますが、ひとつ教えてください。


    No34017に返信(魔界の仮面弁士さんの記事)
    > ■No34016に返信(やむさんの記事)
    >>値をセットすることはできるのですが、桁を補完した customer_code がテキストボックスに反映されません。
    >
    > ValueChanged イベント中で、Value を再編集しているためではないでしょうか。

    ValueChangedイベント内で、Valueを再編すると反映されないのはなぜでしょう。
    確かにイベント中に、head.customer_codeの値が変更されるので
    再度同じイベントが呼び出されますが、
    最終的にhead.customer_code に設定される値は、桁補完された値になります。
    それがコントロールに反映されない理由がわかりません。

    何か根本的な思い違いをしているのでしょうか。



解決み!
違反を報告
引用返信 削除キー/
■34022 / inTopicNo.6)  Re[5]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ 魔界の仮面弁士 大御所(1161回)-(2018/11/06(Tue) 11:12:26)
  • アイコンNo34021に返信(やむさんの記事)
    > ValueChangedイベント内で、Valueを再編すると反映されないのはなぜでしょう。

    自分としては、Binding クラスの内部実装において、
    再入防止策が取られているのだと認識しています。

    https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Binding.cs,bfa78df413fff04f,references


    > 再度同じイベントが呼び出されますが、
    > 最終的にhead.customer_code に設定される値は、桁補完された値になります。

    再入防止が原因となれば、そもそも変更通知イベント以外で処理すれば
    よいわけですから、今回のように、BeginInvoke メソッドとか
    BindingComplete イベントとかで処理することで回避できたのだと想像。
    (変更通知による無限ループに陥らないよう注意)
解決み!
違反を報告
引用返信 削除キー/
■34023 / inTopicNo.7)  Re[6]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ やむ 一般人(4回)-(2018/11/06(Tue) 14:20:02)
  • アイコンNo34022に返信(魔界の仮面弁士さんの記事)
    > 再入防止が原因となれば、そもそも変更通知イベント以外で処理すれば
    > よいわけですから、今回のように、BeginInvoke メソッドとか
    > BindingComplete イベントとかで処理することで回避できたのだと想像。
    > (変更通知による無限ループに陥らないよう注意)

    魔界の仮面弁士さん、重ね重ねありがとうございます。
    無限ループ、その可能性を考慮するのがすっかり抜け落ちておりました。

    今までコントロール側のLeaveイベントで処理をしていたものを
    違う形に変更しようと思い、試しに作ってみたのですが

    「入力された内容を補完し、かつ補完した値を使って別プロパティに値をセットする」

    ことをしようとした場合、そもそもPropertyChangedイベントで拾うのではなく、
    違う方法となるような気がします。
    今回魔界の仮面弁士さんが示してくれた方法は、そのやり方でするなら、こう対処すればいいんじゃない?的なアドバイスだと思いました。

    何か参考になるドキュメント等あればご紹介いただけますと幸いです。
解決み!
違反を報告
引用返信 削除キー/
■34024 / inTopicNo.8)  Re[7]: フォームコントロールへのDataBindingsでプロパティが相互反映されない
□投稿者/ やむ 一般人(5回)-(2018/11/06(Tue) 15:42:18)
  • アイコンもうひとつ。
    PropertyChangedイベントを使用して今回の処理をしようとしたのは、
    自作クラスを格納したBindingListとDataGridViewをDataSourceで紐づけて
    同様のことをしているのですが、そっちは問題なく動作している点もあります。
解決み!
違反を報告
引用返信 削除キー/



トピック内ページ移動 / << 0 >>

このトピックに書きこむ

Mode/  Pass/


- Child Tree -