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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

Q&A

解決済

1回答

3161閲覧

ListBox(WPF)で各アイテムに連番を与える方法

kawauso

総合スコア56

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

0グッド

0クリップ

投稿2017/08/19 05:13

編集2017/08/21 06:14

お世話になっております。

行いたいこと
ListBoxのitemに連番を振りたいと思っています。
ListBoxの並び替え(過去の質問)機能を実装しているので、順番が変われば値を更新したいと思っています。

行ったこと
こちらのItemsControl の各項目表示にインデックス値を使うを参考にAlternationCountプロパティを用いることで、
連番を振ることはできました。
しかし、2番目以降のものを一番上へと並び替えた際に、それの値がAlternationCountの最大値になってしまいます。

(AlternationCount = 10)
(連番: アイテム名)

0: item1
1: item2
2: item3
3: item4

↓ (item2を一番上にもってくる)

9: item2
0: item1
1: item3
2: item4

解決策をご存知の方、よろしくお願いいたします。

追記:
立て続けに質問、申し訳ございません。
たとえば、下記のようなViewModelにIndexを振りたい場合はどのようにすればよろしいでしょうか。

C#

1public class MyItem: BindableBase 2{ 3 public int Index { set; get; } 4 public string ItemName { set; get; } 5 : 6} 7 8private ObservableCollection<MyItem> MyItemCollection { set; get; } = new ObservableCollection<MyItem>() 9{ 10 new MyItem{ ItemName="item1" }, 11 new MyItem{ ItemName="item2" }, 12 new MyItem{ ItemName="item3" }, 13 new MyItem{ ItemName="item4" }, 14 new MyItem{ ItemName="item5" } 15};

XAML

1<ListBox.ItemTemplate> 2 3 <DataTemplate> 4 <StackPanel Orientation="Horizontal"> 5 <TextBlock Text="{Binding Index/> 6 <TextBlock Text=" : " /> 7 <TextBlock Text="{Binding ItemName}" /> 8 </StackPanel> 9 </DataTemplate> 10</ListBox.ItemTemplate>

下記のように記述してみたところ、
<TextBlock Text="{Binding Path=Index, RelativeSource={RelativeSource AncestorType=ListBoxItem}, Converter={StaticResource ItemContainerToIndexConverter}}"/>

このようなエラーが出力されます。
System.Windows.Data Error: 40 : BindingExpression path error: 'Index' property not found on 'object' ''ListBoxItem' (Name='')'. BindingExpression:Path=Index; DataItem='ListBoxItem' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

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

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

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

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

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

guest

回答1

0

ベストアンサー

リスト更新時に ListBoxItems.Reflesh() を呼ぶことでAlternationCountの最大値になってしまう現象は回避できるようです。

ですが、ListBoxの項目がスクロールするほど数が多いとうまくいかないことがあるようですので、別の方法として IValueConverter を使用した例を挙げます


このValueConverterは、入力されたListBoxItemが所属するListBoxでの位置を返します。

C#

1using System; 2using System.Globalization; 3using System.Windows.Controls; 4using System.Windows.Data; 5 6: 7 8 public class ItemContainerToIndexConverter : IValueConverter 9 { 10 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 { 12 var container = value as ContentControl; 13 var itemsControl = ItemsControl.ItemsControlFromItemContainer(container); 14 return itemsControl != null ? itemsControl.Items.IndexOf(container.DataContext) : -1; 15 } 16 17 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 18 { 19 throw new NotImplementedException(); 20 } 21 }

使用例は以下のようになります。
コレクションが変更されたら表示を最新状態にするようにObservableCollectoin<T>.CollectionChangedイベントを使用しています。

C#

1using System.Collections.ObjectModel; 2 3: 4 5 public partial class MainWindow : Window 6 { 7 public ObservableCollection<string> Collection { get; } = new ObservableCollection<string>() 8 { 9 "Item1", 10 "Item2", 11 "Item3", 12 "Item4", 13 "Item5", 14 }; 15 16 public MainWindow() 17 { 18 InitializeComponent(); 19 this.DataContext = this; 20 this.Collection.CollectionChanged += Collection_CollectionChanged; 21 } 22 23 private void Collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 24 { 25 this.listBox.Items.Refresh(); 26 } 27 }
<ListBox x:Name="listBox" ItemsSource="{Binding Collection}"> <ListBox.Resources> <local:ItemContainerToIndexConverter x:Key="ItemContainerToIndexConverter"/> </ListBox.Resources> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Converter={StaticResource ItemContainerToIndexConverter}}"/> <TextBlock Text=" : " /> <TextBlock Text="{Binding}" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

(追記)
データにIndexプロパティを持たせられるのであれば、ValueConverterも使用しない素直な実装になります。
以下の例では項目変更時に全てのIndexを更新するようにしていますが、項目を入れ替える時にその項目のIndexも入れ替える、という方法もあります。

C#

1 public partial class MainWindow : Window 2 { 3 public ObservableCollection<MyItem> Collection { get; } = new ObservableCollection<MyItem>() 4 { 5 new MyItem{ ItemName="item1" }, 6 new MyItem{ ItemName="item2" }, 7 new MyItem{ ItemName="item3" }, 8 new MyItem{ ItemName="item4" }, 9 new MyItem{ ItemName="item5" } 10 }; 11 12 public MainWindow() 13 { 14 InitializeComponent(); 15 this.DataContext = this; 16 17 RefleshCollectionIndex(); 18 this.Collection.CollectionChanged += (s, e) => RefleshCollectionIndex(); 19 } 20 21 public void RefleshCollectionIndex() 22 { 23 for (int i = 0; i < this.Collection.Count; ++i) 24 { 25 this.Collection[i].Index = i; 26 } 27 } 28 } 29 30 // 31 public class MyItem : INotifyPropertyChanged 32 { 33 public event PropertyChangedEventHandler PropertyChanged; 34 protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = null) 35 { 36 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 37 } 38 39 private int _index; 40 public int Index 41 { 42 get { return _index; } 43 set { if (_index != value) { _index = value; RaisePropertyChanged(); } } 44 } 45 46 private string _itemName; 47 public string ItemName 48 { 49 get { return _itemName; } 50 set { if (_itemName != value) { _itemName = value; RaisePropertyChanged(); } } 51 } 52 } 53

投稿2017/08/20 16:53

編集2017/08/21 08:37
neelabo

総合スコア60

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

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

kawauso

2017/08/21 06:14

回答ありがとうございます。 ご提示いただいたサンプルコードは思い通りの振る舞いをしてくれました。非常に助かりました。 質問文には書いていませんでしたが、ViewModelにIndexを割り振りたいと思っております。 質問文に、コードと試してみたことを追記しました。 もしよろしければ、ヒントでも構いませんので、お教えいただければ幸いです。
neelabo

2017/08/21 08:39

Indexプロパティを使用した例を追記しました。
kawauso

2017/08/21 09:47

回答ありがとうございます。 行いたかった実装ができました。大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問