🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
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回答

3319閲覧

標準のコントロールのように動的に配置するユーザコントロールのプロパティ値を動的に設定したい

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 クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

2グッド

0クリップ

投稿2021/04/18 15:20

編集2021/05/16 05:50

前提・実現したいこと

Window(Prism)に対して動的にUsercontrolを配置し、Windowからバインドさせた値を配置するUsercontrol上で表示させたいと考えております。

このとき、Prismフレームワークに乗っかった実装ではないと認識しておりますが、いろいろ試行錯誤で試してみて一番自分がやりやすいと感じた実装法がUsercontrolにプロパティを用意するということでした。

ですが、DependencyProperty.Registerを行うにあたり「PropertyChangedCallback」を定義したのですがWindow側で設定する値が定数でなければ呼ばれない状況です。
Bindingした動的な値もこのPropertyChangedCallbackが呼ばれるようにするためにはどうしたら良いでしょうか?
試しに、TextBlockやLabelで動的に配置したところBindingした動的な値を表示させられたので実装可能と認識しております。

発生している問題・エラーメッセージ

ActionPanelViewModel のオブジェクトに No プロパティが見つかりません。

該当のソースコード

[WindowのXaml]

Xaml

1< !-- 省略 -- 2 Height="360" Width="500" 3 prism:ViewModelLocator.AutoWireViewModel="True"> 4 <Window.Resources> 5 <local:TestViewModel x:Key="ViewModel"/> 6 </Window.Resources> 7 <Grid DataContext="{StaticResource ViewModel}"> 8 <Grid.ColumnDefinitions> 9 <ColumnDefinition Width="7*"/> 10 <ColumnDefinition Width="2*"/> 11 </Grid.ColumnDefinitions> 12 <Label Grid.Column="0" Content="承認フロー名:" Margin="0,0,300,295"/> 13 <TextBox Grid.Column="0" Margin="0,0,130,295" HorizontalAlignment="Right" Width="164" /> 14 <ItemsControl Grid.Column="0" ItemsSource="{Binding Items}" Margin="0,42,0,0.5"> 15 <ItemsControl.ItemsPanel> 16 <ItemsPanelTemplate> 17 <Canvas /> 18 </ItemsPanelTemplate> 19 </ItemsControl.ItemsPanel> 20 <ItemsControl.ItemTemplate> 21 <DataTemplate DataType="local:Item"> 22 <views:ActionPanel No="{Binding No}"/> 23 <!-- Label Content="{Binding No}"/ --> 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 </Grid> 36</Window>

[windowのViewModel]

C#

1public class TestViewModel : BindableBase, INotifyPropertyChanged 2 { 3 //フィールド 4 private static int _xCode=5; 5 private int _yCode; 6 private int _no; 7 Stack<Item> _stack; 8 9 public TestViewModel() 10 { 11 _no = 0; 12 _yCode = 5; 13 _items = new ObservableCollection<Item>(); 14 _stack = new Stack<Item>(); 15 AddCommand = new DelegateCommand(ExecuteAddCommand); 16 DelCommand = new DelegateCommand(ExecuteDelCommand); 17 } 18 19 public string No 20 { 21 get { return _no.ToString(); } 22 } 23 24 25 private ObservableCollection<Item> _items; 26 public ObservableCollection<Item> Items 27 { 28 get { return _items; } 29 } 30 31 private DelegateCommand _addCommand; 32 public DelegateCommand AddCommand { get; } 33 34 private void ExecuteAddCommand() 35 { 36 _no++; 37 Item itm = new Item(_no.ToString(), _xCode, _yCode); 38 _stack.Push(itm); 39 _items.Add(itm); 40 _yCode += 60; 41 } 42 43 private DelegateCommand _delCommand; 44 public DelegateCommand DelCommand { get; } 45 46 private void ExecuteDelCommand() 47 { 48 if (_no > 0) 49 { 50 Item itm = _stack.Pop(); 51 _items.Remove(itm); 52 _yCode -= 60; 53 _no--; 54 } 55 else 56 { 57 MessageBox.Show("これ以上削除できません。"); 58 } 59 } 60 } 61 62 public class Item 63 { 64 public Item(string no, int x, int y) 65 { 66 No = no; 67 X = x; 68 Y = y; 69 } 70 public String No { get; set; } 71 public int X { get; set; } 72 public int Y { get; set; } 73 }

[UserControlのXaml]

Xaml

1< !-- 省略 -- 2 Width="340" Height="60" 3 x:Name="panel" 4 prism:ViewModelLocator.AutoWireViewModel="True"> 5 <Grid > 6 <TextBlock Text="{Binding No, ElementName=panel}" Margin="2,2,313,35" FontSize="14"/> 7     <!--以下は本ユーザコントロールのViewModelにてバインドし表示--> 8 <ComboBox ItemsSource="{Binding People}" SelectedValue="Value" DisplayMemberPath="DisplayValue" 9 SelectedItem="{Binding SelectedAuthority,Mode=TwoWay}" HorizontalAlignment="Left" Height="25" VerticalAlignment="Top" Width="173" Margin="27,0,0,0"/> 10 <ComboBox ItemsSource="{Binding Authority}" SelectedValue="Value" DisplayMemberPath="DisplayValue" 11 SelectedItem="{Binding SelectedAuthority,Mode=TwoWay}" HorizontalAlignment="Left" Margin="210,0,0,0" VerticalAlignment="Top" Width="130" Height="25"/> 12 <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"/> 13 </Grid> 14</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 }

試したこと

上述に記載した通り、TextBlockやLabelではBindingした値が動的に設定され、動的に配置したコントロール上に表示されますが、自作のユーザコントロールでは実現できていない状況です。
どうすれば実現できるかご教授いただけますと幸いです。

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

※上述のWindowはMainWindowのメニューにあるボタンを押下して表示するものです。
なので、「RegionManager」は使用できないと認識しております。

また、動的に配置したユーザコントロール上で設定される情報をWindow側で管理できるような実装をしたいと考えておりますが、これについてもご教授いただける手法がございましたら教えていただけますと幸いです。

TN8001, nori_2👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

DependencyProperty.Registerを行うにあたり「PropertyChangedCallback」を定義したのですがWindow側で設定する値が定数でなければ呼ばれない状況です。

DependencyPropertyPropertyChangedCallbackも関係ありません(提示コードで問題ありません)
DataContextの問題です(なので定数は通ります)

[XAML バインド エラー]ウィンドウに、エラーが出ているはずです(なければ[出力]ウィンドウでも同じ)

重大度レベル データ コンテキスト バインド パス ターゲット ターゲット型 説明 ファイル 行 プロジェクト エラー ActionPanelViewModel No ActionPanel.No、名前 = 'panel' String 型 ActionPanelViewModel のオブジェクトに No プロパティが見つかりません。

つまりもうActionPanelViewModelが、DataContextになっています。
ApprovalFlowRegistViewModel側にバインドするなら、例えばこんな感じで探してこなくてはいけません。

xml

1<views:ActionPanel No="{Binding DataContext.No, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}" />

※上述のWindowはMainWindowのメニューにあるボタンを押下して表示するものです。
なので、「RegionManager」は使用できないと認識しております。

こちらはどうでしょうか?(私はまともにPrismを使っていないのでわかってません)
PopupWindowActionで呼び出したCustomWindow内でRegionを使う - Qiita

また、動的に配置したユーザコントロール上で設定される情報をWindow側で管理できるような実装

K.KATSU2さんが何を指しているのかちょっとわかりませんが、ActionPanelViewModelのことでしょうか?
私ならApprovalFlowRegistViewModel に、ObservableCollection<ActionPanelViewModel>を持たせますかね(もちろんAutoWireViewModelは切ります)


気になった点(余計なお世話かもしれませんが^^;

  • AutoWireViewModelResourcesで、2つApprovalFlowRegistViewModelができている
    何か記載のない特殊な事情があるんでしょうか?ちょっと見たことのない作りです。
  • Canvasを使う意味はあるんでしょうか?(ドラッグ移動とかがあるのかな??)
    これだけ見るとStackPanelItemsPanelを特に指定しない)で十分に見えます。
  • ぐちゃぐちゃマージン(デザイナでドラッグするとなる、"0,0,300,295"のようなマージン)や、固定サイズはやめる
    GridDockPanel等を使ってちゃんとレイアウトしたほうがいいです。環境によってはレイアウトが崩れます。
  • _stackは必要でしょうか?
    Items.RemoveAt(Items.Count - 1);で十分に見えます。
  • 使っていないあるいは使う必要のない変数
    _items_addCommand等。

追記 説明&改善例

xml

1<Window 2 x:Class="Questions333961.Views.ApprovalFlowRegist" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Questions333961.ViewModels" 6 xmlns:prism="http://prismlibrary.com/" 7 xmlns:views="clr-namespace:Questions333961.Views" 8 Width="500" 9 Height="360" 10 prism:ViewModelLocator.AutoWireViewModel="True"> 11 12 <!--AutoWireViewModel="True"だと、prismが自動的にViewModelを作りWindowのDataContextにセットします--> 13 <!--<Window.Resources> 14 <local:ApprovalFlowRegistViewModel x:Key="ViewModel" /> 15 </Window.Resources>--> 16 <!--<DockPanel DataContext="{StaticResource ViewModel}">--> 17 <DockPanel> 18 <StackPanel DockPanel.Dock="Right"> 19 <Button 20 MinWidth="90" 21 Margin="10" 22 Command="{Binding AddCommand}" 23 Content="追加" /> 24 <Button 25 MinWidth="90" 26 Margin="10" 27 Command="{Binding DelCommand}" 28 Content="削除" /> 29 </StackPanel> 30 <DockPanel> 31 <Grid DockPanel.Dock="Top"> 32 <Grid.ColumnDefinitions> 33 <ColumnDefinition Width="Auto" /> 34 <ColumnDefinition /> 35 </Grid.ColumnDefinitions> 36 <Label Content="承認フロー名:" /> 37 <TextBox Grid.Column="1" /> 38 </Grid> 39 <ItemsControl ItemsSource="{Binding Items}"> 40 41 <!--ItemsPanelが無指定だとStackPanelで縦に並びます--> 42 <!--<ItemsControl.ItemsPanel> 43 <ItemsPanelTemplate> 44 <Canvas /> 45 </ItemsPanelTemplate> 46 </ItemsControl.ItemsPanel>--> 47 <ItemsControl.ItemTemplate> 48 <DataTemplate DataType="local:Item"> 49 <views:ActionPanel No="{Binding DataContext.No, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}" /> 50 <!--<views:ActionPanel No="{Binding No}" />--> 51 </DataTemplate> 52 </ItemsControl.ItemTemplate> 53 54 <!--ここも必要ないですしItemのXYもいりません--> 55 <!--<ItemsControl.ItemContainerStyle> 56 <Style TargetType="ContentPresenter"> 57 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 58 <Setter Property="Canvas.Left" Value="{Binding X}" /> 59 </Style> 60 </ItemsControl.ItemContainerStyle>--> 61 </ItemsControl> 62 </DockPanel> 63 </DockPanel> 64</Window>

投稿2021/04/18 22:02

編集2023/07/26 16:00
TN8001

総合スコア9855

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

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

K.KATSU2

2021/04/19 12:18

ご回答いただきましてありがとうございます。問題は解消しました。 また、ご指摘いただい点ごもっともだと感じています。 一部開発途中ですのでこれから使用する予定のものもありますが… 以前は、WinFormアプリで開発していたものでして、 Xamlによる画面デザインが柔軟性があることを知り勉強中でございます。 XAMLを理解する良い方法などございましたら教えていただけますと幸いです。 論理的に構成されているのでしょうが、いまだに理解が不足している部分が多々ある状況です。
K.KATSU2

2021/04/19 12:35

> AutoWireViewModelとResourcesで、2つApprovalFlowRegistViewModelができている についてですが、そもそも仕組みを理解していない状態です。 冗長であれば削除したいと思っています。 また、Canvasを使用している理由は下記のサイトを参考にしているからでして、 ユーザコントロールを動的に配置できる手法が別に適切な手法として存在するのであればそちらを使用したいです。 https://qiita.com/okazuki/items/e7da617887003d0f2899
TN8001

2021/04/19 14:36

> XAMLを理解する良い方法などございましたら教えていただけますと幸いです。 こちらなんかはどうでしょうか? [WPFにおけるGUI構築講座 -座標ベタ書きから脱却しよう- - Qiita](https://qiita.com/YSRKEN/items/686068a359866f21f956 「wpf レイアウト コツ」で検索しました。 > そもそも仕組みを理解していない状態です。 > 冗長であれば削除したいと思っています。 どちらを削っても動くと思いますが、普通はリソースのほうを消しますかね。 > ユーザコントロールを動的に配置できる手法が別に適切な手法として存在するのであればそちらを使用したいです。 「任意の座標に配置したい」というのが要件でしたら別にかまいませんが、今のコードだと縦に並べているだけなので意味がないなと思いました。 今後左右に動いたりドラッグ操作で動かしたりする予定があれば、気にしないでください。 Windowのxamlだけ改善例を追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問