2017-03-06 18 views
0

リストボックスに画像のリストを表示していて、各画像の下にタイトルがあります。データは配列内の各子に対してJObjectのJSON配列です。リストボックスに項目を追加するスピードアップ(コードビハインドまたはxamlバインディング?)

リストボックスアイテムはスタックパネルであり、イメージとテキストはスタックパネルに挿入され、アイテムとしてリストボックスに挿入されます。

唯一の問題は、多くのデータ(40個以上のアイテム)で遅くなることです。

XAMLのデータバインディングがはるかに高速だと聞いたことがありますが、画面上で何かを得ることはできません。

XAMLバインディングは高速化して使用できるようになりますか?理想的には、プログラムをロックすることなく、各項目が利用可能な状態で追加されるように、即座に、または「ポップイン」スタイルにしたいと思っています。データは、ローカルのJSONファイルとローカルイメージから取得されます。

これは、コードの背後にあると同様に良いことができる場合は、素晴らしい。しかし、私は速度を向上させるように見えることはできません。それをスレッドに移動させても、それほど大きな違いはありませんでした。

// Loop through the data 
foreach (dynamic item in this.data.Select((value, i) => new { i, value })) 
{ 
    // Create the image for this item 
    this.images[item.i] = new Image 
    { 
     Width = 278, 
     Height = 178, 
    }; 

    // If the image for this item exists 
    if (File.Exists(item.value["Image"].ToString())) 
    { 
     // The path to this image 
     string imageFilePath = item.value["Image"].ToString(); 
     // Set the image source 
     this.images[item.i].Source = new BitmapImage(new Uri(imageFilePath, UriKind.RelativeOrAbsolute)); 
    } 

    // Create a stack panel to store our item 
    StackPanel stackPanel = new StackPanel 
    { 
     Width = 288, 
     Height = 215, 
    }; 

    // Create the items text 
    TextBlock textBlock = new TextBlock(); 
    textBlock.text = item.value["Text"].ToString(); 

    // Add the Image to the stack panel 
    stackPanel.Children.Add(this.images[item.i]); 
    // Add the text to the stack panel 
    stackPanel.Children.Add(textBlock); 

    // Add the stackpanel to the list 
    this.Items.Add(stackPanel); 
} 

ウィンドウのXAML:

<Window x:Class="MyProject.Windows.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:MyProject" 
     mc:Ignorable="d" 
     Title="Window" Width="800" Height="600"> 

    <Grid> 
     <!-- The list box --> 
     <ListBox x:Name="listBox" /> 
    </Grid> 
</Window> 

をこれは私がバインドしようとしたListBoxコントロールのためのXAMLです。ここ

は、私は背後にあるコードを経由してアイテムを追加してい方法です。画面に何も表示されません。

EDIT:メソッドに後ろにあるコードを移動し、コード内のどこかでそのメソッドを呼び出すと、画像/テキストが画面に表示されます。最初はそれをやっていないのはなぜですか?それは、コード・ビハインド・バージョンと同じくらい遅いです。

<ListBox x:Name="listBox" ItemsSource="{Binding testList}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <VirtualizingStackPanel> 
       <Image Source="{Binding Image}"/> 
       <TextBlock Text="{Binding Text}" FontSize="20" /> 
      </VirtualizingStackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

そして

// List to store our data 
private List<Item> testList { get; set; } 

public MyClass() 
{ 
    // Initialise the test list 
    this.testList = new List<Item>(); 
    // Loop through the data 
    foreach (dynamic item in this.data.Select((value, i) => new { i, value })) 
    { 
     Item item = item.value.ToObject<Item>(); 
     this.testList.Add(item); 
    } 

    this.ItemsSource = this.testList; 
} 

結合XAMLのための背後にあるコードを使用すると、

+0

ToObjectは何をしていますか? 'ToObject'を呼び出す前に、値はどのような型ですか? –

+0

ToObjectはJSON.Netメソッドで、JObjectsを呼び出して特定の型に変換することができます。この場合、アイテムは2つのメンバーを持つクラスImageとText – PersuitOfPerfection

答えて

3

の背後にあるコードでは、あなたのコントロールを作成しないでくださいありがとうございました。代わりにListBoxDataTemplateBindingItemTemplateを使用してください。

public class Model : INotifyPropertyChanged 
{ 
    string _imageFilePath; 
    public string ImageFilePath { get { return _imageFilePath; } set { _imageFilePath = value; RaisePropertyChanged("ImageFilePath"); } } 

    string _text; 
    public string Text { get { return _text; } set { _text = value; RaisePropertyChanged("Text"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void RaisePropertyChanged(string propname) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); 
    } 
} 

あなたの最も重要な仕事は、あなたのデータをループにより、ObservableCollection<Model>を移入するために次のようになります。この2つのプロパティを持つクラスを作成します

:私は最善のアプローチを説明しよう。

public MainWindow() 
{ 
    DataContext = new ViewModel(); 
    InitializeComponent(); 
} 

これは動作するはずです:のDataContextがpropertly設定されているため

public class ViewModel 
{ 
    public ViewModel() 
    { 
     //populate the Models here 
    } 

    ObservableCollection<Model> _models; 
    public ObservableCollection<Model> Models { get { return _models; } set { _models = value; } } 

} 

使用

<ListBox ItemsSource="{Binding Models}"> 
<ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel> 
      <Image Source="{Binding ImageFilePath }"/> 
      <TextBlock Text="{Binding Text}" FontSize="20" /> 
     </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 
</ListBox> 

:このコレクションでは、以下のクラスに入れることができます。

+0

'ListBox'に' DataContext'を指定する必要はありません。特に 'DataContext = {Binding}'は 'DataContext'をそれ自身にバインドしているだけです。 –

+1

ありがとうございます。あなたが正しいです。これは単なる習慣です。 – Ron

+0

ありがとうございます。私が試みたコードと比較して、コードにいくつかの違いがあります。私はこれを渦巻きにして報告します。 – PersuitOfPerfection

関連する問題