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

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

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

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

WPF

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

Q&A

解決済

2回答

7251閲覧

ツリービューで選択した項目を通知したい(WPF)

sa_sa

総合スコア15

C#

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

WPF

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

0グッド

0クリップ

投稿2017/03/15 04:05

編集2017/03/24 11:08

こんにちは。WPFを勉強中の者です。
プログラミング自体あまり明るくないため、具体的な改善点まで教えていただけると嬉しいです。

###前提・実現したいこと
TreeView上で選択状態にある項目を削除できるようにしたいです。
ツリーでの選択状態の通知ができれば解決すると考えています。
ツリーの任意の項目を選択した状態でボタンを押すと削除できるという仕組みにするつもりです。

###発生している問題・エラーメッセージ
ViewModelに存在するコレクションをTreeViewにバインディングさせています。
以前ListBoxで同じことを行った際にはSelectedItemプロパティを使用することで、選択している項目をViewModel側へ通知しましたが、TreeViewのSelectedItemはListBoxのそれとは仕様が異なるのか同じようにいきません。

以下にここまで作ったソースコードを載せます。当初はxamlのTreeViewに
SelectedItem="{Binding SelectedPerson}"
と記述しViewModelにあるSelectedPersonプロパティとバインディングさせ、removeMethodに
Remove(SelectedPerson)
を書くことで選択項目を削除するつもりでした。

###該当のソースコード
TreeViewAddRemoveViewプロジェクト

MainWindow.xaml ------------------------------------------ <Window x:Class="TreeAddRemove.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="20" /> </Grid.RowDefinitions> <TreeView Name="treeview" Grid.Row="0" ItemsSource="{Binding TreeObject.People}"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Name}" /> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> <Button Grid.Row="1" Name="button" Content="RemoveButton" Command="{Binding Person.ChopCommand}" /> </Grid> </Window>
MainWindow.xaml.cs --------------------------------------- using System.Windows; using TreeAddRemoveViewModel; namespace TreeAddRemove { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainWindowViewModel(); } } }

TreeViewAddRemoveViewModelプロジェクト

MainWindowViewModel.cs -------------------------------------------- using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using System.Collections.ObjectModel; namespace TreeAddRemoveViewModel { public class MainWindowViewModel: ViewModelBase { public TreeObject TreeObject { get; private set; } public Person Person { get; private set; } public MainWindowViewModel() { TreeObject = new TreeObject(); Person = new Person(); } } public class TreeObject : ViewModelBase { private ObservableCollection<Person> people; public ObservableCollection<Person> People { get { return people; } set { people = value; } } public TreeObject() { var p = new Person() { Children = { new Person("Human01") { Children = { new Person("Human02"), new Person("Human03") } } } }; p.SetParent(); People = p.Children; } } public class Person : ViewModelBase { public Person() { } public Person(string name) { Name = name; } private string name; public string Name { get { return name; } set { name = value; } } public Person Parent { get; set; } private ObservableCollection<Person> children = new ObservableCollection<Person>(); public ObservableCollection<Person> Children { get { return children; } set { children = value; } } /// <summary> /// 親子関係の設定 /// </summary> public void SetParent() { foreach (var item in Children) { item.Parent = this; item.SetParent(); } } public void AddChild(Person p) { this.Children.Add(p); p.Parent = this; } private void chop() { if(this.Parent != null) { this.Parent.Children.Remove(this); } //this.Parent?.Children.Remove(this); } #region remove Command /// <summary> /// Gets the remove. /// </summary> public RelayCommand ChopCommand { get { return _chopCommand ?? (_chopCommand = new RelayCommand(() => { chop(); })); } } private RelayCommand _chopCommand; #endregion } }

###補足情報(言語/FW/ツール等のバージョンなど)
言語 C#
開発環境 Visual Studio 2013
Microsoft .NETFramework 4.6.1

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

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

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

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

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

guest

回答2

0

ベストアンサー

ソースコードはこっちのほうがきれいに成形されるのでこっちで回答します。

親子関係を定義してあげると、子から親にアクセスできて、その親に対して削除処理をすればいいということですね。

あと、public class Person : ObservableCollection<Person>
を修正ました。Listの継承はやらないほうがいい。

MvvmLightを使ってます。

cshap

1 2using GalaSoft.MvvmLight; 3using GalaSoft.MvvmLight.Command; 4using System.Collections.ObjectModel; 5 6namespace WpfApp2.ViewModel 7{ 8 public class MainWindowViewModel: ViewModelBase 9 { 10 private ObservableCollection<Person> people; 11 public ObservableCollection<Person> People 12 { 13 get { return people; } 14 set { people = value; } 15 } 16 17 private Person selectedPerson = null; 18 public Person SelectedPerson 19 { 20 get { return selectedPerson; } 21 set { selectedPerson = value; } 22 } 23 24 public MainWindowViewModel() 25 { 26 var p = new Person() 27 { 28 Children ={ new Person("Human01") 29 { 30 Children = { 31 new Person("Human02"), 32 new Person("Human03") 33 } 34 } 35 } 36 }; 37 p.SetParent(); 38 People = p.Children; 39 } 40 41 } 42 43 public class Person : ViewModelBase 44 { 45 public Person() { } 46 public Person(string name) 47 { 48 Name = name; 49 } 50 private string name; 51 public string Name 52 { 53 get { return name; } 54 set { name = value; } 55 } 56 public Person Parent { get; set; } 57 public ObservableCollection<Person> Children { get; set; } = new ObservableCollection<Person>(); 58 59 /// <summary> 60 /// 親子関係の設定 61 /// </summary> 62 public void SetParent() 63 { 64 foreach (var item in Children) 65 { 66 item.Parent = this; 67 item.SetParent(); 68 } 69 } 70 71 public void AddChild(Person p) 72 { 73 this.Children.Add(p); 74 p.Parent = this; 75 } 76 77 private void chop() 78 { 79 this.Parent?.Children.Remove(this); 80 } 81 #region remove Command 82 /// <summary> 83 /// Gets the remove. 84 /// </summary> 85 public RelayCommand ChopCommand 86 { 87 get { return _chopCommand ?? (_chopCommand = new RelayCommand(() => { chop(); })); } 88 } 89 private RelayCommand _chopCommand; 90 #endregion 91 92 } 93}

投稿2017/03/22 09:26

編集2017/03/22 16:58
kiichi54321

総合スコア1984

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

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

sa_sa

2017/03/24 08:58

追記のほど、ありがとうございます。 MvvmLightというものが初見でしたので少し躓きましたが調べてなんとかインストールしました。 少し確認させていただきたいのですが、 >public ObservableCollection<Person> Children { get; set; } = new ObservableCollection<Person>(); はこのままではエラーになるため、 private ObservableCollection<Person> children; public ObservableCollection<Person> Children { get{ return children; } set{ children = value; } } と書き換えましたが問題ありませんか? それとchopメソッドの >this.Parent?.Children.Remove(this); にあるParentのあとの?は単なるタイプミスでしょうか?それとも何か意味のあるものなのでしょうか?一応タイプミスと判断して?は取り去って使わせていただいています。 プログラミング自体ほぼ初心者なもので、見当外れなことをやったり聞いたりしてしまっていたらすみません… その上でなのですが、ボタンのCommandプロパティをChopCommandにバインディングしましたが、chop()内の処理を実行できずエラーを吐き出してしまいます。 質問ばかりで心苦しいですがお答えいただけるとありがたく思います。
kiichi54321

2017/03/24 09:09

あー、開発環境が Visual Studio 2013 か。これらは、たぶん2015あたりで新しい文法ですね。http://www.buildinsider.net/language/csharplang/0600 ここを参考にするといいかと。個人で使うなら、無料なので Visual Studio 2017を使うといいともいます。エラーは、おそらくNullチェックができてない、ParentがNullになっているので、適切にParentを設定するようにするといいと思います。
sa_sa

2017/03/24 09:52

私の環境では使えない文法だったのですね。理解いたしました。 貼っていただいたリンクを拝見いたしましたが、これに従うと this.Parent?.Children.Remove(this); とは、Parentがnullならnullを返し、Parentがnullでなければ this.Children.Remove(this)の結果を返すというイメージで間違いありませんか?
kiichi54321

2017/03/24 10:04

これを省略しているだけです。 if ( this.Parent != null) { this.Parent.Children.Remove(this); }
sa_sa

2017/03/24 11:20

ありがとうございます。そのように書き換えて実行してみました。 結果としては、ツリーのどの項目を選択してもParentがnullのままであるためchop()メソッドを素通りするということになりました。 これは選択内容が通知できていないからと考えるべきでしょうか。 なお、記載していただいたコードのままではButtonのCommandプロパティにPersonクラスのChopCommandをバインディングできないためViewModelの内容を少しいじっています。 質問文に載せているソースコードを現状のものに更新したためよろしければそちらをご覧いただきたく思います。
kiichi54321

2017/03/24 12:34 編集

想定していたのは、こういう風に、アイテムの近くに削除ボタンが置くことです。 <TreeView Name="treeview" Grid.Row="0" ItemsSource="{Binding TreeObject.People}"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal"> <Button Content="x" Command="{Binding ChopCommand}"></Button> <TextBlock Text="{Binding Name}" /> </StackPanel> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>
sa_sa

2017/03/27 01:37

そういうことだったのですね。私の考えていた仕様とは少し違ったために気が付きませんでした。 おかげさまで正しく動作するようになりました。 何度も質問に答えていただき本当にありがとうございました!
guest

0

質問の答えにはなっていませんが、
Personの立場で、削除するという感じで
Personにdelete用の ICommandを実装すると削除するはできますね。

投稿2017/03/15 04:56

kiichi54321

総合スコア1984

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

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

sa_sa

2017/03/21 03:12

ご回答ありがとうございます。 しかし当方の知識不足によりそれだけでは理解がしきれなかったため、もしよろしければもう少し詳細を伺ってもよろしいでしょうか? 現在MainWindowViewModelに記述している private ICommand removeElement; public ICommand RemoveElement { get { return removeElement = new DelegateCommand(removeMethod); } } private void removeMethod() { } をPersonクラスの方に移すことになるのでしょうか? そうしますとremoveMethodにはどのような記述をすることになるのでしょうか? ご面倒をおかけしますがよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問