Listbox binding - wpf

Hello I have problem with binding data to Listbox. In shortway... I want list all my Skydrive files.
My XAML
<TextBlock Height="35" HorizontalAlignment="Left" Margin="9,6,0,0" Name="infoTextBlock" Text="" VerticalAlignment="Top" Width="Auto" />
<my:SignInButton Name="signInButton1" ClientId="<correct ClientId>" Scopes="wl.signin wl.basic wl.skydrive" Branding="Windows" TextType="SignIn" SessionChanged="signInButton1_SessionChanged" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="198,-6,0,0" />
<StackPanel Height="578" HorizontalAlignment="Left" Margin="10,50,0,0" Name="StackContentPanel" VerticalAlignment="Top" Width="440">
<ListBox Height="465" Name="FileList" Width="380" ItemsSource="{Binding Files}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
My class and cs.
namespace EReader.ViewModel
{
public class File
{
public File()
{}
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
}
}
public class FilesManager
{
public ObservableCollection<string> Files;
public FilesManager()
{
Files = new ObservableCollection<string>();
}
}
namespace EReader
{
public partial class MainPage : PhoneApplicationPage
{
private LiveConnectClient client;
// Constructor
public MainPage()
{
InitializeComponent();
}
private void signInButton1_SessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
{
if (e.Status == LiveConnectSessionStatus.Connected)
{
client = new LiveConnectClient(e.Session);
infoTextBlock.Text = "Signed in.";
client.GetCompleted +=
new EventHandler<LiveOperationCompletedEventArgs>(OnGetCompleted);
client.GetAsync("/me/skydrive/files/");
}
else
{
infoTextBlock.Text = "Not signed in.";
client = null;
}
}
void OnGetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
//Gdy uda nam się podłaczyc do konta skydrive
if (e.Error == null)
{
signInButton1.Visibility = System.Windows.Visibility.Collapsed;
#region Nazwa użytkownika
string firstName = "";
string lastName = "";
if (e.Result.ContainsKey("first_name") ||
e.Result.ContainsKey("last_name"))
{
if (e.Result.ContainsKey("first_name"))
{
if (e.Result["first_name"] != null)
{
firstName = e.Result["first_name"].ToString();
}
}
if (e.Result.ContainsKey("last_name"))
{
if (e.Result["last_name"] != null)
{
lastName = e.Result["last_name"].ToString();
}
}
infoTextBlock.Text =
"Hello, " + firstName +" "+ lastName + "!";
}
else
{
infoTextBlock.Text = "Hello, signed-in user!";
}
#endregion
#region Wszyskite pliki
List<object> data = (List<object>)e.Result["data"];
FilesManager fileManager = new FilesManager();
foreach (IDictionary<string,object> items in data)
{
File file = new File();
file.Name= items["name"].ToString();
fileManager.Files.Add(file.Name);
}
FileList.ItemsSource = fileManager.Files;
#endregion
}
else
{
infoTextBlock.Text = "Error calling API: " +
e.Error.ToString();
}
}
}

Files must be a property, not a field.
Furthermore {Binding Name} must be {Binding} instead, because a string has no Name property.

This has to be a public property:
public ObservableCollection<string> Files;
should be
public ObservableCollection<string> Files {get;set;}
Then your binding will work

Related

WPF - How to change content of ContentControl clicking on TreeViewItem?

I am working on a WPF project and I am facing a problem. I have searched for 2 days a solution but I have never found anything that could help me...
I have a TreeView with different data types inside and a ContentControl that shows views corresponding to these different data types. I want, when I click on a TreeViewItem that, depending on the data type contained in this TreeViewItem, it changes the view in the ContentControl.
I reached to execute different commands depending on the TreeviewItem selected but it never changes the view...
Does somebody have an answer or an idea that could help me ?
I use this for my TreeView :
<TreeView x:Name="networkTree" ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="490" TreeViewItem.Selected="GetHeaderSelectedItem"/>
It executes this :
public class NetworkConfigViewModel : BindableBase
{
private IRegionManager regionManager;
private bool _showRDConf;
private bool _showNetworkConf;
private bool _showDeviceInfo;
public NetworkConfigViewModel(IRegionManager regionManager)
{
this.regionManager = regionManager;
regionManager.RegisterViewWithRegion("NetworkConfigInfoRegion", typeof(NetworkConfigInfoView));
regionManager.RegisterViewWithRegion("RDConfigurationRegion", typeof(RDConfigurationView));
regionManager.RegisterViewWithRegion("DeviceInfoRegion", typeof(DeviceInfoView));
ShowNetworkConfCommand = new DelegateCommand(NetworkConf);
ShowRDConfCommand = new DelegateCommand(RDConf);
ShowDeviceInfoCommand = new DelegateCommand(DevInfo);
_showNetworkConf = true;
_showRDConf = false;
_showDeviceInfo = false;
}
public bool ShowRDConf
{
get
{
return _showRDConf;
}
set
{
SetProperty(ref _showRDConf, value);
}
}
public bool ShowNetworkConf
{
get
{
return _showNetworkConf;
}
set
{
SetProperty(ref _showNetworkConf, value);
}
}
public bool ShowDeviceInfo
{
get
{
return _showDeviceInfo;
}
set
{
SetProperty(ref _showDeviceInfo, value);
}
}
public DelegateCommand ShowNetworkConfCommand { get; set; }
public DelegateCommand ShowRDConfCommand { get; set; }
public DelegateCommand ShowDeviceInfoCommand { get; set; }
private void NetworkConf()
{
ShowRDConf = false;
ShowDeviceInfo = false;
ShowNetworkConf = true;
System.Windows.Forms.MessageBox.Show("Commande ShowNetConf executée :\nShowNetworkConf="+ShowNetworkConf.ToString()+"\nShowRDConf="+ShowRDConf.ToString() + "\nShowDeviceInfo=" + ShowDeviceInfo.ToString());
}
private void RDConf()
{
ShowNetworkConf = false;
ShowDeviceInfo = false;
ShowRDConf = true;
System.Windows.Forms.MessageBox.Show("Commande ShowRConf executée :\nShowRDConf="+ShowRDConf.ToString()+"\nShowNetworkConf="+ShowNetworkConf.ToString() + "\nShowRDeviceInfo=" + ShowDeviceInfo.ToString());
}
private void DevInfo()
{
ShowNetworkConf = false;
ShowRDConf = false;
ShowDeviceInfo = true;
System.Windows.Forms.MessageBox.Show("Commande ShowDeviceInfo executée :\nShowDeviceInfo=" + ShowDeviceInfo.ToString() + "\nShowNetworkConf=" + ShowNetworkConf.ToString() + "\nShowRDConf=" + ShowRDConf.ToString());
}
public void ChangeNetworkView(TreeView tree)
{
TreeViewItem tvi = null;
tvi = tree.SelectedItem as TreeViewItem;
if (tvi != null)
{
if (tvi.Tag.ToString() == "Network")
{
ShowNetworkConfCommand.Execute();
}
else if(tvi.Tag.ToString()=="RD")
{
ShowRDConfCommand.Execute();
}
else if (tvi.Tag.ToString() == "VD")
{
ShowDeviceInfoCommand.Execute();
}
}
}
}
And for my ContentControl :
<ContentControl x:Name="RDView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowRDConf, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="RDConfigurationRegion"/>
<ContentControl x:Name="NetworkView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowNetworkConf, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="NetworkConfigInfoRegion"/>
<ContentControl x:Name="DeviceView" x:FieldModifier="public" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Grid.ColumnSpan="2" Visibility="{Binding Path=ShowDeviceInfo, Converter={StaticResource Convert}}" prism:RegionManager.RegionName="DeviceInfoRegionq"/>
Thank you by advance

wpf ListItem SelectedValue Object is always null

I have a simple ListBox and a TextBox as under.I want to display the selectedvalue property of Listbox in the textbox,but my ViewModel's selected object is always null.
What am i missing here?
My XAML
<StackPanel>
<Canvas>
<TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding CurrentRec.Name,Mode=OneWay}" />
<ListBox x:Name="AllMatching" Width="{Binding ElementName=TxtMail,Path=Width}" Height="100" Canvas.Top="54" Canvas.Left="36" DisplayMemberPath="Name" SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedValue="Name" SelectedValuePath="Name" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" />
<Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
</Canvas>
My ViewModel:
public class VM_Data : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int p_ID;
public double p_SP, p_CP;
public string p_Name;
public List<DM_Data> AllData;
public DM_Data CurrentRec;
public VM_Data()
{
LoadData();
}
public int ID
{
get { return p_ID; }
set
{
if (p_ID != value)
{
RaisePropertyChangedEvent("ID");
p_ID = value;
}
}
}
public double SP
{
get { return p_SP; }
set
{
if (p_SP != value)
{
RaisePropertyChangedEvent("SP");
p_SP = value;
}
}
}
public double CP
{
get { return p_CP; }
set
{
if (p_CP != value)
{
RaisePropertyChangedEvent("CP");
p_CP = value;
}
}
}
public string Name
{
get { return p_Name; }
set
{
if (p_Name != value)
{
RaisePropertyChangedEvent("Name");
p_Name = value;
}
}
}
private void LoadData()
{
AllData = new List<DM_Data>();
string[] strNames = "Jatinder;Shashvat;shashikala;shamsher;shahid;justin;jatin;jolly;ajay;ahan;vijay;suresh;namita;nisha;negar;zenith;zan;zen;zutshi;harish;hercules;harman;ramesh;shashank;mandeep;aman;amandeep;amarjit;asim;akshay;amol;ritesh;ritivik;riz;samana;samaira;bhagwandass;bhagwan;bhawna;bhavna".Split(';');
for(int i=0;i<=strNames.GetUpperBound(0);i++)
{
DM_Data NewRec = new DM_Data();
NewRec.CP = new Random().Next(200, 400);
NewRec.SP = new Random().Next(1, 10);
NewRec.ID = i + 1;
NewRec.Name = strNames[i];
AllData.Add(NewRec);
}
AllData = AllData.OrderBy(item => item.Name).ToList();
}
private void RaisePropertyChangedEvent(string Property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
}
}
My DataModel
public class DM_Data
{
public int p_ID;
public double p_SP, p_CP;
public string p_Name;
public int ID
{
get { return p_ID; }
set { p_ID = value; }
}
public double SP
{
get { return p_SP; }
set { p_SP = value; }
}
public double CP
{
get { return p_CP; }
set { p_CP = value; }
}
public string Name
{
get { return p_Name; }
set { p_Name = value; }
}
MainWindow.Xaml.cs
public partial class MainWindow : Window
{
VM_Data ViewModel;
public MainWindow()
{
InitializeComponent();
ViewModel = new VM_Data();
this.DataContext = ViewModel;
AllMatching.ItemsSource = ViewModel.AllData;
}
private void cmdtest_Click(object sender, RoutedEventArgs e)
{
DM_Data crec = ViewModel.CurrentRec;
}
}
CurrentRec must be a property that raises the PropertyChanged event:
private DM_Data _currentRec;
public DM_Data CurrentRec
{
get { return _currentRec; }
set { _currentRec = value; RaisePropertyChangedEvent("CurrentRec"); }
}
In the code you have posted, it is a field and you cannot bind to fields:
public DM_Data CurrentRec;
You can't bind to fields! CurrentRec must be a property. At now it is a field.
Why do you set ItemsSource in code-behind? Set it in XAML.
You should call RaisePropertyChangedEvent after you've changed backing field, not before.
It is not right pattern for events raising: if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(Property)); } You need to save event delegate to variable first or use ?.Invoke.
Don't create new instances of Random on every iteration of loop because you will get equal values. Create the only one outside of the loop and use it.
What you are doing is kind of MVVM, but not really.
Here is a quick fix anyway:
Please take a look at the Bindings.
<StackPanel>
<Canvas>
<TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}" />
<ListBox x:Name="AllMatching"
Width="{Binding ElementName=TxtMail,Path=Width}"
Height="100"
Canvas.Top="54"
Canvas.Left="36"
DisplayMemberPath="Name"
SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto" />
<Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
</Canvas>
</StackPanel>
I think you get the idea at: Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}".
Aditional Information
First:
You fire to early dude. Please first assign the value and then say its changed.
if (p_Name != value)
{
RaisePropertyChangedEvent("Name");
p_Name = value;
}
Second:
Use a ObservableCollection<DM_Data> to let your ListBox know about changes.
Third:
Use the posibility of Binding
Remove AllMatching.ItemsSource = ViewModel.AllData; and go like
<ListBox x:Name="AllMatching"
ItemsSource="{Binding Path=AllData}"
...
/>
And after all of this - please man check out some tutorials. And also refactor your code from VM_Data to DataViewModel thank you sir.

Silverlight Treeview inline HierarchicalDataTemplate binding issue

I have MyCollection of MyPOCO object (that has two string properties).
When I try to implement a HierarchicalDataTemplate into a treeview the binding is not working, I get the class name.
I know that if i take out the datatemplate from the control everything works fine but i am interested to see why this example is not working.
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource testVM}}">
<sdk:TreeView Margin="8,8,8,111" ItemsSource="{Binding MyCollection}">
<sdk:HierarchicalDataTemplate ItemsSource="{Binding MyPOCO}">
<sdk:HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Property1}"/>
<TextBlock Text="{Binding Property2}"/>
</StackPanel>
</DataTemplate>
</sdk:HierarchicalDataTemplate.ItemTemplate>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView>
</Grid>
Here is the ViewModel also.
namespace MyPOCProject
{
public class MyPOCO
{
private string property1;
public string Property1
{
get { return property1; }
set { property1 = value; }
}
private string property2;
public string Property2
{
get { return property2; }
set { property2 = value; }
}
public MyPOCO(string p1, string p2)
{
property1 = p1;
property2 = p2;
}
}
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<MyPOCO> myCollection;
public ObservableCollection<MyPOCO> MyCollection
{
get { return myCollection; }
set { myCollection = value; RaisePropertyChanged("MyCollection"); }
}
public MyViewModel()
{
MyPOCO _poco1 = new MyPOCO("aaa1", "bbb1");
MyPOCO _poco2 = new MyPOCO("aaa2", "bbb2");
MyPOCO _poco3 = new MyPOCO("aaa3", "bbb3");
MyCollection = new ObservableCollection<MyPOCO>() { _poco1, _poco2, _poco3 };
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
So what am I doing wrong?
AGAIN ... I am interested in this particular example. I want to know what's wrong with this example and why.
Thanks.
The code you posted is not hierarchical, In other words: The MyPOCO Class is not containing a property MyCollection<MYPOCO> Children.
Here is an example for the HierarchicalDataTemplate
Xaml:
<sdk:TreeView x:Name="MyTreeView"
HorizontalAlignment="Left"
ItemsSource="{Binding MyCollection}"
Width="200" Height="280">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Header}"/>
<sdk:HierarchicalDataTemplate.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Header}"/>
</sdk:HierarchicalDataTemplate>
</sdk:HierarchicalDataTemplate.ItemTemplate>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</sdk:TreeView>
Codebehind classes:
public class MyPoco
{
public MyPoco(string header, int sampleChildrenCount)
{
this.Header = header;
this.Children = new ObservableCollection<MyPoco>();
if (sampleChildrenCount > 0)
{
for (int i = 0; i < sampleChildrenCount; i++)
{
string newHeader = String.Format("Test {0}", sampleChildrenCount * i);
var myPoco = new MyPoco(newHeader, sampleChildrenCount - 1)
this.Children.Add(myPoco);
}
}
}
public string Header { get; set; }
public ObservableCollection<MyPoco> Children { get; set; }
}
public class MyViewModel
{
public MyViewModel()
{
MyCollection = new ObservableCollection<MyPoco>();
for (int i = 0; i < 6; i++)
{
this.MyCollection.Add(new MyPoco(String.Format("Test {0}", i), 5));
}
}
public ObservableCollection<MyPoco> MyCollection { get; set; }
}
Codebehind startup:
public MainPage()
{
public MainPage()
{
InitializeComponent();
MyTreeView.DataContext = new MyViewModel();
}
}

Load images to listbox through dialog.Trouble with binding

I should load images to listbox.I have a trouble when I choose images, to listbox added only border without nothing and only one, I have debuged my code and in collection 6 bitmap images, but loaded only 1 border.
1.That is my class Album:
public class Album : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
private string description;
public string Description
{
get
{
return description;
}
set
{
description = value;
OnPropertyChanged(new PropertyChangedEventArgs("Description"));
}
}
private List<BitmapImage> images;
public List<BitmapImage> Images
{
get
{
return images;
}
set
{
images = value;
OnPropertyChanged(new PropertyChangedEventArgs("Images"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public Album() { }
public Album(string name, string description, List<BitmapImage> files)
{
Name = name;
Description = description;
Images = files;
}
}
2.That my code for child window.When i push button create, I write name, description, and add some photos(please check my method for add is it correct).
public partial class DialogCreate : ChildWindow
{
private List<BitmapImage> temps = new List<BitmapImage>();
private string tempName;
private string tempDescription;
public List<BitmapImage> Temps
{
get { return temps; }
set { temps = value; }
}
public string TempName
{
get { return tempName; }
set { tempName = value; }
}
public string TempDescription
{
get { return tempDescription; }
set { tempDescription = value; }
}
private OpenFileDialog addPhoto;
public DialogCreate()
{
InitializeComponent();
addPhoto = new OpenFileDialog();
addPhoto.Multiselect = true;
addPhoto.Filter = "Image files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
tempName = txtGetName.Text;
tempDescription = txtGetDescription.Text;
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
bool result = (bool)addPhoto.ShowDialog();
if (!result)
return;
IEnumerable<FileInfo> file = addPhoto.Files;
foreach (FileInfo files in file)
{
Stream s = files.OpenRead();
BitmapImage i = new BitmapImage();
i.SetSource(s);
temps.Add(i);
}
}
}
3.After that I return to:
private void CreateButton_Click(object sender, RoutedEventArgs e)
{
dialogAlbum = new DialogCreate();
dialogAlbum.Show();
dialogAlbum.Closed += delegate
{
albums.Add(new Album(dialogAlbum.TempName, dialogAlbum.TempDescription, dialogAlbum.Temps));
AlbumScroll.ItemsSource = albums;
lsPhoto.ItemsSource = albums;
};
}
4.That my xaml:
<ListBox Style="{StaticResource ListBoxStyle}" ItemsSource="{Binding Images}" Margin="121,38,171,23" x:Name="lsPhoto" Grid.Column="1" Grid.Row="2" Height="144" Width="600">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="100" Height="100">
<Image x:Name="listPhotos" Source="{Binding}" Width="Auto" Height="Auto"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Please help me, what I did wrong?Or give your advertise.
I created a new class something like this
public class ImageInformation:INotifyPropertyChanged
{
public string Name { get; set; }
public BitmapImage ImageInfo { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
I replaced all the places where you use BitmapImage and in mainpage.xaml
<ListBox x:Name="lsPhoto" Grid.RowSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Height="25" Width="25">
<Image Height="25" Width="25" Source="{Binding ImageInfo}"></Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With these two changes and other impacted changes, my Listbox shows the image that was selected by the user. If you need the solution i tried, send me a mail.

DataVirtualization and ListView UI freeze

I tried to find a solution with asynchronous DataProvider, but everywhere is bound to a static class, but I need a dynamic binding to different objects.
I tried to use the this solution but my UI still freezes. Anyone can explain why I get this behavior and how do I make UI active.
Application XAML file:
<Window x:Class="WpfApplication_async.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication_async"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:RecordValueDataTemplateSelector x:Key="myDataTemplateSelector"/>
<DataTemplate x:Key="ComboBoxTemplate">
<ComboBox Width="{Binding Path=ColumnDef.ColumnWidth,Mode=OneTime}"
ItemsSource="{Binding Path=viewEntityList,Mode=TwoWay}"
SelectedIndex="{Binding Path=Index, Mode=TwoWay}">
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=Text,Mode=TwoWay}" Width="{Binding Path=ColumnDef.ColumnWidth,Mode=OneTime}"/>
</DataTemplate>
<DataTemplate x:Key="HeaderTextBlockTemplate">
<TextBlock Width="{Binding Path=ColumnWidth,Mode=OneTime}" Text="{Binding Path=ColumnName,Mode=TwoWay}" ToolTip="{Binding Path=ColumnName}" />
</DataTemplate>
<DataTemplate x:Key="ListBoxTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" Width="80"/>
<ListBox ItemsSource="{Binding Path=Items}"
ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<DockPanel>
<ListBox Name="headerListBox" MinHeight="20" DockPanel.Dock="Top"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False"
ItemTemplate="{StaticResource HeaderTextBlockTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<ScrollViewer Name="listScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<ListView Name="listView" SelectionMode="Extended"
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.IsDeferredScrollingEnabled="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ListBoxTemplate}" >
</ListView>
</ScrollViewer>
</DockPanel>
</ScrollViewer>
<Button Grid.Row="1" Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
</Window>
My dataProvider classes:
using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Windows.Data;
using System.Windows;
using DataVirtualization;
using System.Threading;
//using System.Threading;
namespace WpfApplication_async
{
public enum MySubKeyValueType { StringValue=0, ListValue=1 }
public class MySection : IItemsProvider<MyRecord>
{
/// <summary>
/// Fetches the total number of items available.
/// </summary>
/// <returns></returns>
public int FetchCount()
{
//Thread.Sleep(1000);
return Records.Count;
}
/// <summary>
/// Fetches a range of items.
/// </summary>
/// <param name="startIndex">The start index.</param>
/// <param name="count">The number of items to fetch.</param>
/// <returns></returns>
public IList<MyRecord> FetchRange(int startIndex, int count)
{
//Thread.Sleep(1000);
if (startIndex > Records.Count) startIndex = Records.Count;
if (startIndex + count > Records.Count) count = Records.Count - startIndex;
return Records.ToList().GetRange(startIndex, count).ToList();
}
public MySection()
{
Records = new ObservableCollection<MyRecord>();
}
public ObservableCollection<MyRecord> Records { get; set;}
}
public class MyRecord : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public MyRecord()
{
Items = new ObservableCollection<MySubKeyValue>();
}
private string key;
public string Key {
get {
return key;
}
set {
//if (Key!=null && this.Parent is MySection && (this.Parent as MySection).SectionDefinition.IsNumberedKeys)
// return;
key = value;
OnPropertyChanged("Key");
}
}
ObservableCollection<MySubKeyValue> items = new ObservableCollection<MySubKeyValue>();
public ObservableCollection<MySubKeyValue> Items
{
get {
return items;
}
set {
items = value;
OnPropertyChanged("NumberedColumnText");
}
}
}
public class MySubKeyValue : DependencyObject, INotifyPropertyChanged
{
private ColumnDefinition columnDef = null;
public ColumnDefinition ColumnDef
{
get
{
if (columnDef == null)
return columnDef = new ColumnDefinition();
return columnDef;
}
set { columnDef = value; }
}
public MySubKeyValue(string str = null)
{
Text = str;
ValueType = MySubKeyValueType.StringValue;
IsValidData = true;
ErrorMessage = "error";
}
private string text;
public MySubKeyValueType ValueType { get; set; }
public string Text
{
get
{
if (text == null) return String.Empty;
return text;
}
set
{
if (text != value)
{
text = value;
OnPropertyChanged("Text");
}
}
}
public bool isValidData = true;
public bool IsValidData
{
get { return isValidData; }
set
{
if (isValidData != value)
{
isValidData = value;
OnPropertyChanged("IsValidData");
}
}
}
public string ErrorMessage { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
public class StringValue : MySubKeyValue
{
public StringValue(string str = null)
{
ValueType = MySubKeyValueType.StringValue;
Text = str;
}
}
public class ListValue : MySubKeyValue
{
private int index;
public int Index
{
get { return index; }
set
{
index = value;
if (index > -1 && index < valueEntityList.Count)
{
base.Text = valueEntityList[index];
IsValidData = true;
}
else
IsValidData = false;
OnPropertyChanged("Index");
}
}
public List<string> valueEntityList { get; set; }
public List<string> viewEntityList { get; set; }
public ListValue(string str, ListValue l)
{
ValueType = MySubKeyValueType.ListValue;
valueEntityList = l.valueEntityList;
viewEntityList = l.viewEntityList;
base.Text = str;
Index = valueEntityList.FindIndex(v => v == str);
}
public ListValue(List<string> _vals = null, List<string> _views = null, string str = "")
{
Index = -1;
ValueType = MySubKeyValueType.ListValue;
valueEntityList = new List<string>();
viewEntityList = new List<string>();
if (_vals != null)
if (_views != null && _views.Count == _vals.Count)
{
valueEntityList.AddRange(_vals);
viewEntityList.AddRange(_views);
}
else
{
valueEntityList.AddRange(_vals);
viewEntityList.AddRange(_vals);
}
base.Text = str;
Index = valueEntityList.FindIndex(v => v == str);
}
}
public class ColumnDefinition : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public ColumnDefinition(string name = "", int width = 80)
{
ColumnName = name;
ColumnWidth = width;
}
public string ColumnName { get; set; }
private int columnWidth;
public int ColumnWidth
{
get { return columnWidth; }
set { columnWidth = value; OnPropertyChanged("ColumnWidth"); }
}
}
}
MainWindow:
namespace WpfApplication_async
{
public partial class MainWindow : Window
{
MySection sec1,sec2;
bool isSec1 = true;
public MainWindow()
{
InitializeComponent();
sec1 = new MySection();
for(int i=0;i<50;i++){
MyRecord rec = new MyRecord();
rec.Key = i.ToString();
for(int j=0;j<20;j++){
rec.Items.Add(new StringValue("abc"));
rec.Items[rec.Items.Count - 1].ColumnDef = new ColumnDefinition(j.ToString());
}
sec1.Records.Add(rec);
}
sec2 = new MySection();
for (int i = 0; i < 50; i++)
{
MyRecord rec = new MyRecord();
rec.Key = i.ToString();
for (int j = 0; j < 20; j++)
{
rec.Items.Add(new ListValue(new List<string> { "a", "b" }, new List<string> { "a", "b" }, "a"));
rec.Items[rec.Items.Count - 1].ColumnDef = new ColumnDefinition(j.ToString());
}
sec2.Records.Add(rec);
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (isSec1)
//listView.DataContext = sec2;
listView.DataContext = new AsyncVirtualizingCollection<MyRecord>(sec2, 10, 30 * 1000);
else
//listView.DataContext = sec1;
listView.DataContext = new AsyncVirtualizingCollection<MyRecord>(sec1, 10, 30 * 1000);
isSec1 = !isSec1;
}
}
}
I found a simple solution. Instead of setting DataContext, I added items manually with low priority. UI does not freeze. Goal is achieved.
foreach (var r in sec.Records)
{
listView.Dispatcher.Invoke((new Action(delegate()
{
listView.Items.Add(r);
})), DispatcherPriority.SystemIdle);
}

Resources