3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C#】WPFにおける動的なUserControlの追加

Last updated at Posted at 2023-02-28

こんにちわ。女性はひつじではありません、人間ですとかよく言われます。

簡単なんだけど何故か詰まったので書いてみる(とにかくこういう事がとても多い)。初学者でも比較的カンタンに試せるように書いたので気軽にやってみてほしい。

詰まったときに こういう記事をたまたま見つけて、自分のUserコントロールを追加したら見切れたんでTeratailで質問してみたことがある。Heightを指定しないといけないとの事である。

もちろん、Canvasに自作のコントロールを追加するなんて事はしないでいい(やってて違和感があったんですぐ辞めた)。
通常はStackPaneとかに追加する。

自作のUserControl(外観)

image.png

<UserControl x:Class="WpfApp3.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp3"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
<!--Grid 要素は書き換え-->
    <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
     <!--コピーここから-->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto" >

        </Grid.ColumnDefinitions>
        <TextBox x:Name="ArgumentEditor" Grid.Row="0" Grid.Column="2" Margin="-10,3,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="380"/>

        <RadioButton />

        <ContentControl HorizontalAlignment="Left" Name="SelectorLabelCon">
            <TextBlock  
                    Name="ParamLabel"
                TextWrapping="Wrap"
                    
               Grid.Row="0"
               Grid.Column="2"
                HorizontalAlignment="Left"
                 Text="パラメータ名"  Margin="15,3,15,0"/>
        </ContentControl>
    <!--ここまで-->
    </Grid>
</UserControl>

WPF(XAML)はこういうとき、本当に便利である。
コピペは一気に貼るよりは要素毎に貼り付けることをオススメする。

これを新しいプロジェクトを作って適用してみる。

最近のwindows11ではプロジェクトの作成時にまで管理者権限を要求するようになっている。めんどくさい。

面倒だからUserControl1でいいだろう。
image.png

MainForm側はStackPnelを追加して適当な名前を付ける(だけ)。

 <Grid>
        <StackPanel x:Name="mainPanel">                  
        </StackPanel>
</Grid>

あとはLoadイベントでも追加しておく
Loadイベントはタブコントロール切り替えなどで複数回呼ばれる可能性が高いのでコンストラクタの方がいいかも知れない。

呼び出し実装

 private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            
            
            for(int Count = 0  ; Count < 10  ; Count++ )
            {
                Thickness marthick = new Thickness(-40, 0, 0, 0);

                var useC = new UserControl1() 
                {
                    Margin = marthick,
                    FontSize = 14,
                    Width = 480,
                    
                    Name = "ParamSelector" + $"{Count}"
                    //名前と番号を振っておく
                };

                if (!mainPanel.Children.Contains(useC))
                    mainPanel.Children.Add(useC);
                    
            }

実行結果

image.png

大して時間は掛からない筈である。

動的なコントロールの操作方法はNameプロパティの割り振りを始め、コンストラクタでイベント登録などをゴリゴリ書かないといけないのでちょっと大変かもしれない。

そのうち手を出したいDataBind、ViewModel
https://qiita.com/soi/items/12ceea4efcf31c1a7b93

自作のアプリではこれをとにかく書きまくっている。ユーザーコントロール側で書いた方がいい実装もあると思う。ちょっと重そうだし。
DataBindingを駆使すると実装側は比較的省力化出来る筈なのでそのうちやりたいです。DataContextをTwoWayに設定出来るらしい。

イベントのsenderで見分ける場合は、WPFコントロールの親要素をや子要素を見つける方法がblogで公開されてるので調べて併用してほしい。

親要素や子要素を列挙せずにコントロールのNameプロパティで見分ける方法

記事を書きました。

3
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?