質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

4415閲覧

[WPF][Xaml]Window側からボタン押下でユーザコントロールを動的に配置したり、プロパティ値を更新したりしたい

K.KATSU2

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

XAML

XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2021/04/20 22:15

編集2021/04/30 15:27

前提・実現したいこと

Window(Prism)側からボタン押下で動的にUsercontrolを配置したり、配置したユーザコントロールのプロパティ値を更新したりしたいと考えています。

いろいろなネット上より上述ができそうなことはわかっておりますが、冗長なプログラミングになる気がして手間取っております。

参考にさせていただいたURLは以下になります。
https://qiita.com/tera1707/items/8d24b21a05ad84a1c92f

該当のソースコード

[WindowのXaml]

Xaml

1<Window x:Class="TEST.Views.TESTFlowRegist" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:prism="http://prismlibrary.com/" 5 xmlns:views="clr-namespace:TEST.Views" 6 Height="360" Width="500" 7 prism:ViewModelLocator.AutoWireViewModel="True"> 8 <Grid> 9 <Grid.ColumnDefinitions> 10 <ColumnDefinition Width="7*"/> 11 <ColumnDefinition Width="2*"/> 12 </Grid.ColumnDefinitions> 13 <Label Grid.Column="0" Content="承認フロー名:" Margin="0,0,300,295"/> 14 <TextBox Grid.Column="0" Margin="0,0,130,295" HorizontalAlignment="Right" Width="164" /> 15 <ItemsControl Grid.Column="0" ItemsSource="{Binding Items}" Margin="0,42,0,0.5"> 16 <ItemsControl.ItemsPanel> 17 <ItemsPanelTemplate> 18 <Canvas /> 19 </ItemsPanelTemplate> 20 </ItemsControl.ItemsPanel> 21 <ItemsControl.ItemTemplate> 22 <DataTemplate> 23 <views:ActionPanel No="{Binding DataContext.No, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}" /> 24 </DataTemplate> 25 </ItemsControl.ItemTemplate> 26 <ItemsControl.ItemContainerStyle> 27 <Style TargetType="ContentPresenter"> 28 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 29 <Setter Property="Canvas.Left" Value="{Binding X}" /> 30 </Style> 31 </ItemsControl.ItemContainerStyle> 32 </ItemsControl> 33 <Button Content="追加" Command="{Binding AddCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="90" Height="35"/> 34 <Button Content="削除" Command="{Binding DelCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,68,0,0" VerticalAlignment="Top" Width="90" Height="35"/> 35 <Button Content="Or" Command="{Binding DelCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="90" Height="35"/> 36 <Button Content="And" Command="{Binding DelCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,165,0,0" VerticalAlignment="Top" Width="90" Height="35"/> 37 </Grid> 38</Window>

[UserControlのXaml]

Xaml

1<UserControl x:Class="TEST.Views.ActionPanel" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:prism="http://prismlibrary.com/" 5 Width="340" Height="60" 6 x:Name="panel" 7 prism:ViewModelLocator.AutoWireViewModel="True"> 8 <Grid > 9 <TextBlock Text="{Binding No, ElementName=panel}" Margin="2,2,313,35" FontSize="14"/> 10     <!--以下は本ユーザコントロールのViewModelにてバインドし表示--> 11 <ComboBox ItemsSource="{Binding People}" SelectedValue="Value" DisplayMemberPath="DisplayValue" 12 SelectedItem="{Binding SelectedAuthority,Mode=TwoWay}" HorizontalAlignment="Left" Height="25" VerticalAlignment="Top" Width="173" Margin="27,0,0,0"/> 13 <ComboBox ItemsSource="{Binding Authority}" SelectedValue="Value" DisplayMemberPath="DisplayValue" 14 SelectedItem="{Binding SelectedAuthority,Mode=TwoWay}" HorizontalAlignment="Left" Margin="210,0,0,0" VerticalAlignment="Top" Width="130" Height="25"/> 15 <Label Content="{Binding Indicator}" HorizontalAlignment="Left" Margin="0,30,0,0" VerticalAlignment="Top" Width="80" Height="30" FontSize="14" FontWeight="Bold" FontFamily="Yu Gothic UI Semibold"/> 16 </Grid> 17</UserControl>

[UserControlのクラスコード]

C#

1 public partial class ActionPanel : UserControl 2 { 3 public string No 4 { 5 get { return (string)this.GetValue(ActionPanel.NoProperty); } 6 set { this.SetValue(ActionPanel.NoProperty, value); } 7 } 8 9 public ActionPanel() 10 { 11 InitializeComponent(); 12 } 13 14 15 public static readonly DependencyProperty NoProperty = DependencyProperty.Register( 16 "No",typeof(string),typeof(ActionPanel), 17 new FrameworkPropertyMetadata("No", new PropertyChangedCallback(OnNoChanged))); 18 19 private static void OnNoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 20 { 21 ActionPanel ctl = d as ActionPanel; //null checks omitted 22 string s = e.NewValue as string; //null checks omitted 23 if(ctl== null || s == string.Empty) 24 { 25 ctl.No = ""; 26 } 27 else 28 { 29 ctl.No = s; 30 } 31 } 32 }

具体的に実現したいこと

Window側に配置した追加・削除ボタンでユーザコントロールを動的に配置したいです。
このとき、縦に並べられればよく、現在Canvasを使って配置しておりますがこれより簡潔な手法があればご教授いただけますと幸いです。

加えて、デフォルトでユーザコントロールを配置した際に表示されるLabelコントロールの「↓」の表示をAnd・Orボタンにより「Or」や「And」に更新したいと思っております。

こうするためには参考にしたURLの通りICommandをユーザコントロール側に実装する必要がありますでしょうか?
もっと良い方法がございましたらご教授いただけますと幸いです。

補足情報(FW/ツールのバージョンなど)

・C#
・VisualStudio 2019
・.Net Framework 4.7.2
・使用しているフレームワーク:Prism

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

はっきり言って丸投げ感が半端ないですが、どんどんおかしな方向に行っているので回答します(前回回答分ぐらいは反映して頂きたかったのですが。。)

前回の質問では何をしようとしているのかが見えなかったのでスルーしましたが、DependencyPropertyなどは全く必要ありません。
これに関してはPrismが悪いと思っているので、K.KATSU2さんのせいではありません。

ちょっと日本語でうまく説明できないのでコードを見てください。

MainWindow

xml

1<Window 2 x:Class="Questions334328.Views.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 7 xmlns:prism="http://prismlibrary.com/" 8 xmlns:viewmodels="clr-namespace:Questions334328.ViewModels" 9 xmlns:views="clr-namespace:Questions334328.Views" 10 Width="500" 11 Height="360" 12 d:DataContext="{d:DesignInstance Type=viewmodels:MainWindowViewModel}" 13 prism:ViewModelLocator.AutoWireViewModel="True" 14 mc:Ignorable="d"> 15 16 <Window.Resources> 17 <Style TargetType="Button"> 18 <Setter Property="Margin" Value="10" /> 19 <Style.Triggers> 20 <Trigger Property="Command" Value="{x:Null}"> 21 <Setter Property="IsEnabled" Value="False" /> 22 </Trigger> 23 </Style.Triggers> 24 </Style> 25 <DataTemplate DataType="{x:Type viewmodels:ActionPanelViewModel}"> 26 <views:ActionPanel /> 27 </DataTemplate> 28 </Window.Resources> 29 30 <DockPanel> 31 <StackPanel MinWidth="100" DockPanel.Dock="Right"> 32 <Button Command="{Binding AddCommand}" Content="追加" /> 33 <Button 34 Command="{Binding DelCommand}" 35 CommandParameter="{Binding Items/}" 36 Content="削除" /> 37 <Button Command="{Binding Items/OrCommand}" Content="Or" /> 38 <Button Command="{Binding Items/AndCommand}" Content="And" /> 39 </StackPanel> 40 41 <DockPanel> 42 <DockPanel DockPanel.Dock="Top"> 43 <Label Content="承認フロー名:" /> 44 <TextBox /> 45 </DockPanel> 46 <!-- IsSynchronizedWithCurrentItem="True"がないと / が利かないので注意 --> 47 <ListBox 48 HorizontalContentAlignment="Stretch" 49 IsSynchronizedWithCurrentItem="True" 50 ItemsSource="{Binding Items}" /> 51 </DockPanel> 52 </DockPanel> 53</Window>

cs

1using System.Windows; 2 3namespace Questions334328.Views 4{ 5 public partial class MainWindow : Window 6 { 7 public MainWindow() 8 { 9 InitializeComponent(); 10 } 11 } 12}

cs

1using Prism.Commands; 2using Prism.Mvvm; 3using System.Collections.ObjectModel; 4 5namespace Questions334328.ViewModels 6{ 7 public class MainWindowViewModel : BindableBase 8 { 9 public ObservableCollection<ActionPanelViewModel> Items { get; } = new ObservableCollection<ActionPanelViewModel>(); 10 11 public DelegateCommand AddCommand { get; } 12 public DelegateCommand<ActionPanelViewModel> DelCommand { get; } 13 14 public MainWindowViewModel() 15 { 16 AddCommand = new DelegateCommand(ExecuteAddCommand); 17 DelCommand = new DelegateCommand<ActionPanelViewModel>(ExecuteDelCommand, CanExecuteDelCommand) 18 .ObservesProperty(() => Items.Count); // アイテムがなければ押せない どのプロパティを監視してCanExecuteDelCommandを走らせるかをラムダ式(式木)で指定 19 } 20 21 private void ExecuteAddCommand() 22 { 23 Items.Add(new ActionPanelViewModel { No = Items.Count + 1, }); 24 } 25 26 private bool CanExecuteDelCommand(ActionPanelViewModel arg) 27 { 28 return 0 < Items.Count; 29 } 30 private void ExecuteDelCommand(ActionPanelViewModel item) 31 { 32 Items.Remove(item); 33 for (var i = 0; i < Items.Count; i++) Items[i].No = i + 1; // No振り直し 34 } 35 } 36}

ActionPanel

xml

1<UserControl 2 x:Class="Questions334328.Views.ActionPanel" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 7 xmlns:viewmodels="clr-namespace:Questions334328.ViewModels" 8 d:DataContext="{d:DesignInstance Type=viewmodels:ActionPanelViewModel}" 9 d:DesignHeight="60" 10 d:DesignWidth="340" 11 mc:Ignorable="d"> 12 <StackPanel> 13 <Grid> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition Width="Auto" MinWidth="20" /> 16 <ColumnDefinition Width="173*" /> 17 <ColumnDefinition Width="130*" /> 18 </Grid.ColumnDefinitions> 19 <TextBlock FontSize="14" Text="{Binding No}" /> 20 <ComboBox 21 Grid.Column="1" 22 Margin="10,0" 23 DisplayMemberPath="DisplayValue" 24 ItemsSource="{Binding People}" 25 SelectedItem="{Binding SelectedAuthority, Mode=TwoWay}" 26 SelectedValue="Value" /> 27 <ComboBox 28 Grid.Column="2" 29 Margin="10,0" 30 DisplayMemberPath="DisplayValue" 31 ItemsSource="{Binding Authority}" 32 SelectedItem="{Binding SelectedAuthority, Mode=TwoWay}" 33 SelectedValue="Value" /> 34 </Grid> 35 36 <Label 37 Content="{Binding Indicator}" 38 FontFamily="Yu Gothic UI Semibold" 39 FontSize="14" 40 FontWeight="Bold" /> 41 </StackPanel> 42</UserControl>

cs

1using System.Windows.Controls; 2 3namespace Questions334328.Views 4{ 5 public partial class ActionPanel : UserControl 6 { 7 public ActionPanel() 8 { 9 InitializeComponent(); 10 } 11 } 12}

cs

1using Prism.Commands; 2using Prism.Mvvm; 3using System; 4 5namespace Questions334328.ViewModels 6{ 7 public class ActionPanelViewModel : BindableBase 8 { 9 private int _No; 10 public int No { get => _No; set => SetProperty(ref _No, value); } 11 12 private string _Indicator = "↓"; 13 public string Indicator { get => _Indicator; set => SetProperty(ref _Indicator, value); } 14 15 public DelegateCommand OrCommand { get; } 16 public DelegateCommand AndCommand { get; } 17 18 public ActionPanelViewModel() 19 { 20 OrCommand = new DelegateCommand(ExecuteOrCommand/*() => Indicator = "Or"*/); 21 AndCommand = new DelegateCommand(ExecuteAndCommand/*() => Indicator = "And"*/); 22 } 23 24 private void ExecuteOrCommand() 25 { 26 Indicator = "Or"; 27 } 28 private void ExecuteAndCommand() 29 { 30 Indicator = "And"; 31 } 32 } 33}

質問コードではItemDataTemplateActionPanelになり、DataContextActionPanelViewModelがインジェクションされるという流れです。
ロジック上は不要なItemがあったり、ViewModelがインジェクションされるため「どういじればいいんだ?」となります。

回答コードはActionPanelViewModelDataTemplateActionPanelになり、DataContextActionPanelViewModelをそのまま引き継ぎます。
ActionPanelViewModelの増減やプロパティの変更が、そのままViewに反映されます。

言葉以上にシンプルで非常にすっきりしていると感じられると思います^^

OrCommandAndCommandActionPanelViewModel側で実装しましたが、メイン側に移したければDelCommandと同じようにするだけです。

{Binding Items/}等の/については↓を参照してください。
データ バインディングの概要 - WPF .NET Framework | Microsoft Docs

方法: 階層データでマスター詳細パターンを使用する - WPF .NET Framework | Microsoft Docs


過去にも何度かPrism関連で回答しているのですが、おかしなことになっていることが非常に多いです。
PrismはUserControlViewModelをセットで生成するため、こういった勘違いを誘発している気がします。

WPFに精通した方が大規模開発する場合は有用なんだろうとは思いますが、私はどうも好きになれません^^;

投稿2021/04/21 09:23

編集2023/07/26 16:10
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

K.KATSU2

2021/04/21 22:17

引き続きご回答くださり誠にありがとうございます。 xamlによるデザイン(コントロール配置)など大変勉強になりました。 現在、コードビハインド側を勉強しているところですが、 (いったんそのままコードを使用させているつもりですが) 追加ボタンを押下しても「No」がインクリメントされないところや Andボタンや Orボタンを押下しても「↓」が「And」や「Or」の表示に変わらない 状態となっている状況です。 自力で解決できるのが私としても理想ですが、この点について何かご共有いただけることが ございましたらご教授いただけますと幸いです。 加えて、ラムダ式のような「_ => 」の表現は初めて見ました。 これはどういう動きになりますでしょうか?
TN8001

2021/04/22 05:00

> 追加ボタンを押下しても「No」がインクリメントされないところ ExecuteAddCommand() 自体は通ってるわけですね?(アイテムは増える) > Andボタンや Orボタンを押下しても「↓」が「And」や「Or」の表示に変わらない 押せるようにはなるんですね?(選択してボタンの活性が変わる) どちらも一番ありそうなのはActionPanelの ViewModelLocator.AutoWireViewModel="True" が残ってるパターンですね。"False"にしてください。 Prism 8.0から既定でオンになっているので注意です。 > 加えて、ラムダ式のような「_ => 」の表現は初めて見ました。 > これはどういう動きになりますでしょうか? _ => 0 < Items.Count ここのことでしょうか?これはラムダ式です。 回答をできるだけメソッドに書き換えました。どうでしょうか?
K.KATSU2

2021/04/22 13:35

ご回答くださり誠にありがとうございます。 「ViewModelLocator.AutoWireViewModel="True"」が原因でした。 「_ => 0 < Items.Count」は返り値に”0 < Items.Count”の評価がTrueかFalseで返ると認識しておりますが、引数に_を指定すると何を意味することになりますでしょうか?
TN8001

2021/04/22 13:56

あぁ _ が引っかかってたのですね。 まあ xでもaでもitemでも何でもいいのですが、使うつもりのない変数に慣例的に _ を使ったりしていました。 しかし最近のC#では本当に使えなくなっています。 [破棄 - C# ガイド | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/discards DelCommandは何を削除をするかのために引数で選択中のアイテムをCommandParameterで渡す必要がありますが、CanExecuteDelCommandには選択中のアイテムは必要ありません。 総数が0以上かが分かればいい(アイテムがないときは削除ボタンは不活性)ので「引数を使いません」という表明です。 とはいえxと書いても誰も文句は言いませんw
TN8001

2021/04/22 14:18

本当は未選択時もDelボタンを押せないというほうがいいですね。 しかしViewModelに選択中のアイテムのようなプロパティが必要になるし、本題ではないのでそこまでやりませんでした^^;
K.KATSU2

2021/04/24 12:54

ご回答ありがとうございます。本当に勉強になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問