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

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

■34935 / inTopicNo.1)  LINQでControlsをEnable=Falseに設定
  
□投稿者/ Wan 一般人(41回)-(2021/10/09(Sat) 10:35:03)
  • アイコン環境/言語:[Windows10 VisualStudio2019 VB.net WindowsForm] 
    分類:[.NET] 

    配置されたCheckBoxを全てFalseに設定したいです。
    
    For Each LopCntrol As Control In Me.Controls
     If TypeOf LopCntrol Is CheckBox Then
       LopCntrol.Enabled = False
      End If
    Next
    
    としていたのですが、折角なのでLINQでやろうと
    
     Me.Controls.Cast(Of Control).Where(Function(n) TryCast(n, CheckBox) IsNot Nothing).Select(Function(s) s.Enabled = False)
    
    に変更したところ上手く動きません。
    
    Dim Chkbox = Me.Controls.Cast(Of Control).Where(Function(n) TryCast(n, CheckBox) IsNot Nothing)
    For Each Lop In Chkbox
     Lop.Enabled = False
    Next
    
    なら、上手く動きます。
    1行で実現する(ForEachを使わないで)方法が分かりません。
    
    詳しい方いらっしゃいましたら、ご教授頂けないでしょうか?
    宜しくお願い致します。
    

マルチポストを報告
違反を報告
引用返信 削除キー/
■34936 / inTopicNo.2)  Re[1]: LINQでControlsをEnable=Falseに設定
□投稿者/ Hongliang 大御所(609回)-(2021/10/09(Sat) 12:06:50)
  • アイコンそもそも論として、LINQは副作用のある(オブジェクトの状態を変更する)式を想定していません。
    その傍証として、VBに用意されているクエリ式に使えるキーワードにSelectはあってもUpdateは存在していません。
    https://docs.microsoft.com/ja-jp/dotnet/visual-basic/language-reference/queries/

    なので、はっきり言ってしまえばFor Eachしてください。
    ただしTypeOf...Isなどの代わりにOfType拡張メソッドは使用できます。
    IEnumerableのうち、Of Tで指定したオブジェクトだけを列挙する拡張メソッドです。
    For Each (Dim cb In Me.Controls.OfType(Of CheckBox)())
    ' cbは必ずCheckBoxであり、CheckBox以外のコントロールは列挙されない

    むりやりこねくり回せばできないでもないですが、かえって読みづらくなるだけです。
    Select拡張メソッドは遅延評価なのでそのあとその場で評価する必要があるなど直感的でないし。
違反を報告
引用返信 削除キー/
■34937 / inTopicNo.3)  Re[1]: LINQでControlsをEnable=Falseに設定
□投稿者/ 魔界の仮面弁士 大御所(1404回)-(2021/10/09(Sat) 17:57:37)
  • アイコンNo34935に返信(Wanさんの記事)
    > Me.Controls.Cast(Of Control).Where(Function(n) TryCast(n, CheckBox) IsNot Nothing).Select(Function(s) s.Enabled = False)

    .ToArray / .ToList や Array.ForEach などは「即時実行」されますが、
    .Where / .Select は、「遅延実行」であるためです。
    (この違いは LINQ プロバイダの実装依存です)

    遅延実行という性質を持つがゆえに、.Where や .Select で終わる LINQ 処理は、
    For Each や .ToArray() などを呼び出すまでは、実際には処理されません。


    > 1行で実現する(ForEachを使わないで)方法が分かりません。

    どうしてもワンライナーで記述したければ
     Array.ForEach(Me.Controls.OfType(Of CheckBox)().ToArray(), Sub(chk) chk.Enabled = False)
    あるいは
     Me.Controls.OfType(Of CheckBox)().ToList().ForEach(Sub(chk) chk.Enabled = False)
    と書けます。
    ForEach メソッドの引数には、Sub(x As T) 相当の Action(Of T) を指定します。


    しかし、今回のケースでいえば、素直に
     For Each chk In Me.Controls.OfType(Of CheckBox)()
      chk.Enabled = False
     Next
    とした方が良いと思います。可読性面でも効率面でも。


    なお、Me 直下だけでなく、Panel や GroupBox などの子孫階層にある
    コントロールも列挙したい場合は、再帰呼び出しが必要となります。

    たとえば後述の 拡張メソッドを用意しておくと、
     Me.Controls.OfType(Of CheckBox)()
    の部分を
     Me.GetControls(Of CheckBox)()
    に置き換えることで、子孫要素の CheckBox もすべて列挙されます。蛇足までに。


    Friend Module ControlExtensions
     <System.Runtime.CompilerServices.Extension>
     Public Function GetControls(Of T As Control)(this As Control) As IEnumerable(Of T)
      Dim controls = this.Controls.OfType(Of Control)()
      Return controls.OfType(Of T)().Concat(controls.SelectMany(Of T)(AddressOf GetControls(Of T)))
     End Function
    End Module
違反を報告
引用返信 削除キー/
■34938 / inTopicNo.4)  Re[2]: LINQでControlsをEnable=Falseに設定
□投稿者/ Wan 一般人(42回)-(2021/10/09(Sat) 18:36:09)
  • アイコン
    Hongliang様、魔界の仮面弁士様
    早速のご指南有難う御座います。
    
    魔界の仮面弁士様のおっしゃる通り
    For Each chk In Me.Controls.OfType(Of CheckBox)()
     chk.Enabled = False
    Next
    で、やるのが近い将来自分のコードを見た時に
    なにやってるんだ?ってことにならず、ベストだと思いました。
    
    いつも、適切なご指導大変助かっております。
    有難う御座いました。
    

解決み!
違反を報告
引用返信 削除キー/



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

このトピックに書きこむ

Mode/  Pass/


- Child Tree -