Progress bars are not updating - c#

I've got a problem with {Binding CurrentProgress} value of Progressbar control inside of a Listview. Within my code I'm able to add few items which has couple of properties with CurrentProgress property as well. Items are adding in a proper way, yet only ONE progressbar's updating. Here's the code:
MODEL:
sealed public class Mp3Model : INotifyPropertyChanged
{
public string Name { get; set; }
private double _currentProgress;
public double CurrentProgress
{
get
{
return _currentProgress;
}
set
{
_currentProgress = value;
OnPropertyChanged("CurrentProgress");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<ListView ItemsSource="{Binding Mp3List}">
<ListView.View>
<GridView>
<GridViewColumn
Width="140"
DisplayMemberBinding="{Binding Name}"
Header="Track Name" />
<GridViewColumn Width="300" Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="320">
<ProgressBar
Height="40"
Margin="10"
IsIndeterminate="{Binding IsIndeterminate}"
Maximum="100"
Minimum="0"
Visibility="{Binding IsProgressDownloadVisible}"
Value="{Binding CurrentProgress}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding CurrentProgress, StringFormat={}{0:0}%}"
Visibility="{Binding IsPercentLabelVisible}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding ConvertingLabelText}"
Visibility="{Binding IsConvertingLabelVisible}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding IsOperationDone}"
Visibility="{Binding IsOperationDoneLabelVisible}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
VIEW-MODEL (Method)
private void SaveVideoToDisk()
{
Task.Factory.StartNew(() =>
{
long currentLocalProgress = 0;
this._fileHelper = new FileHelper();
this._model = new Mp3Model();
using (var service = Client.For(YouTube.Default))
{
using (var video = service.GetVideo(YoutubeLinkUrl))
{
_fileHelper.DefaultTrackName = video.FullName;
_fileHelper.DefaultTrackPath = _fileHelper.Path + "\\" + _fileHelper.DefaultTrackName;
_fileHelper.DefaultTrackHiddenPath = _fileHelper.HiddenPath + "\\" + _fileHelper.DefaultTrackName;
_fileHelper.TmpTrackPath = _fileHelper.PreparePathForFFmpeg(_fileHelper.DefaultTrackHiddenPath);
_model = new Mp3Model()
{
Name = _fileHelper.DefaultTrackName,
IsProgressDownloadVisible = Visibility.Visible,
IsPercentLabelVisible = Visibility.Visible,
IsConvertingLabelVisible = Visibility.Hidden,
IsOperationDoneLabelVisible = Visibility.Hidden,
ConvertingLabelText = Consts.ConvertingPleaseWait,
CurrentProgress = 0,
};
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
this._mp3List.Add(_model);
}));
using (var outFile = File.OpenWrite(_fileHelper.TmpTrackPath))
{
using (var progressStream = new ProgressStream(outFile))
{
var streamLength = (long)video.StreamLength();
progressStream.BytesMoved += (sender, args) =>
{
currentLocalProgress = args.StreamLength * 100 / streamLength;
_model.CurrentProgress = currentLocalProgress;
Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
};
video.Stream().CopyTo(progressStream);
}
}
//ExtractAudioFromVideo(_fileHelper.TmpTrackPath);
}
}
});
}
Place of the ProgressBar Binded value:
progressStream.BytesMoved += (sender, args) =>
{
currentLocalProgress = args.StreamLength * 100 / streamLength;
_model.CurrentProgress = currentLocalProgress;
Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
};
Does anyone has any idea?

Trying to guess: you update a _model field which will be overriden each time you call the save video to disk method. This may only work if only one call of this method can be done by instance of the class (but as we don't have the clas, we don't know if it's the list or the video).
So I would say that invoking twice the method stops the first _model instance from being updated (as the lambda captures the variable holding the object)

xaml looks okey to me, but I had similar problems, I fixed as follows:
add Mode=OneWay to the Value="{Binding CurrentProgress, Mode=OneWay}".
Also whenever you update CurrentProgress use the Dispatcher: Application.Current.Dispatcher.Invoke(() => CurrentProgress++);
I hope it can helps you to find the solution.
Edit: Just a suggestion, I use the following OnPropertyChanged, so you don't have to write the name of the properties everytime =D.
protected void OnPropertyChange([CallerMemberName] string inPropertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(inPropertyName));

Related

Effecting a Label from one Tabitem of a Tabcontrol from a button from another Tabitem of the Same Tabcontrol (using MVVM, WPF)

My Situation:
I'm trying to affect a label from one TabItem of a TabControl by clicking a Button on another TabItem of the same TabControl.
I'm currently having a hard time figuring out why the property of my TextBox textBoxTyp won't change its value even after updating the property. The binding is correct an a button right next to the TextBox (on the same TabItem) that's bound exactly like the other Button from the other `Tabitem, works perfectly fine. I'm using the MVVM pattern and databinding.
Here the code of the TabControl itself
<TabControl Name="TabSpaces"
SelectedIndex="{Binding TabIndex, Mode=TwoWay, Source={StaticResource vm_Für_Typenschild}}"
Background="White" Margin="0,0,0,-4">
<TabItem DataContext="{Binding TypneschildVM, Source={StaticResource vm_Für_Typenschild}}"
FontSize="15" Foreground="White" FontWeight="Bold" Background="#401746"
Header="Datei" Margin="0,0,-60,0">
<view:DateiV/>
</TabItem>
<TabItem MouseLeftButtonDown="SelectedTypenschild" Loaded="Typenschild_Loaded"
FontSize="15" Height="50" Foreground="White" FontWeight="Bold"
Background="#401746" Header="Typenschild" BorderBrush="#FFACACAC"
Margin="56,0,-128,0">
<view:TypenschildVM Width="Auto" Height="Auto" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" Margin="1,0"/>
</TabItem>
</TabControl>
Here the code from the view of the TabItem with the button that should affect the TextBox
<Button Command="{Binding ReadXmlAndInsertIntoDialogsIntoTypenSchild_Command, Source={StaticResource vm_Für_Typenschild}}"
FontSize="25" x:Name="button_Datei_entfernen" Foreground="White"
Content="Datei entfernen" HorizontalAlignment="Center" Margin="476,468,476,215"
VerticalAlignment="Center" Width="326" Height="70">
</Button>
Here the code from the functions that should change the property ( ReadXmlAndInsertIntoDialogsIntoTypenSchild & CompareXmlWithJsonAndInsertIntoDialog )
namespace WPF_App_RFID_SpinOff.ViewModel
{
public class TypneschildVM : INotifyPropertyChanged, ICommand
{
private string CompareXmlWithJsonAndInsertIntoDialog(string XmlFileStringToCheck, string IdFromJsonFile)
{
string ValueTopass = "";
string line = "";
StringReader StringReaderOfXmlFile = new StringReader(XmlFileStringToCheck);
while ((line = StringReaderOfXmlFile.ReadLine()) != null)
{
if (line.Contains(IdFromJsonFile) == true)
{
int IndexRightNow = line.IndexOf('V');
int IndexWhereValueStart = line.IndexOf('V');
int CounterToGetValue = 0;
for (CounterToGetValue = IndexWhereValueStart + 1; CounterToGetValue < line.Length; CounterToGetValue++)
{
if (line[CounterToGetValue] != '"' && line[CounterToGetValue] != '=' && line[CounterToGetValue] != '/' && line[CounterToGetValue] != '>')
{
ValueTopass += line[CounterToGetValue];
}
}
}
}
return ValueTopass;
// Console.WriteLine(TypenschildM_ToUse.Hardwareversion);
}
public void ReadXmlAndInsertIntoDialogsIntoTypenSchild(object parameter)
{
int OpenBracketCount = 0;
string IdFromJsonFile = "";
string StringOfJsonFile = StaticFunc.ProvideJsonFile();
string StringOfXmlFile = StaticFunc.ProvideXMLFile();
string StringOfInformationforTypenschildFromXml = GetPartOfXmlFileForTypenSchild(StringOfXmlFile);
string StringOfInformationforTypenschildFromJson = GetPartOfJsonFileForTypenSchild(StringOfJsonFile);
string BlockOfDataforCertainValue = " ";
Console.WriteLine("test");
foreach (char character in StringOfJsonFile)
{
if (character == '{')
{
OpenBracketCount++;
}
if (OpenBracketCount >= 1)
{
BlockOfDataforCertainValue += character;
if (character == '}')
{
Console.WriteLine(BlockOfDataforCertainValue);
IdFromJsonFile = lookOutForID(BlockOfDataforCertainValue);
PropTest = CompareXmlWithJsonAndInsertIntoDialog(StringOfXmlFile, IdFromJsonFile);
OnPropertyChanged("PropTest");
}
}
}
}
#region ICommandSchnittstelle
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
throw new NotImplementedException();
}
#endregion
public TypneschildVM()
{
TypenschildM TypenschildM_ToUse = TypenschildM.Instance;
LeseXMLAus = new RelayCommand(ReadXMLFileForTypenschildVM, StaticFunc.enableExecute);
ReadXmlAndInsertIntoDialogsIntoTypenSchild_Command = new RelayCommand(ReadXmlAndInsertIntoDialogsIntoTypenSchild, StaticFunc.enableExecute);
startButtoon_Command = new RelayCommand(ReadXmlAndInsertIntoDialogsIntoTypenSchild, StaticFunc.enableExecute);
}
}
}
Heres The Binding of my Textbox
<TextBox IsReadOnly="True"
Text="{Binding PropTest, Source={StaticResource vm_Für_Typenschild}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="textBoxTyp" Height="22" Margin="243,93,133,0" TextWrapping="Wrap"
VerticalAlignment="Top" Background="#FFF3F3F3" Grid.Column="2"/>

How to get Binding name from DataTemplate

I'm trying to sort a ListView by it's headers.
I'm following this MSDN example, with the alternation given here - where this line works if I were to use direct binding:
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
string sortString = ((Binding)headerClicked.Column.DisplayMemberBinding).Path.Path
But problem is I'm not binding the columns directly using DisplayMemberBinding="{Binding PVNum}" but rather I am using CellTemplate:
<ListView.Resources>
<DataTemplate x:Key="NumberTemplate">
<TextBlock Text="{Binding PVNum}" TextAlignment="Center" />
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.Columns>
<GridViewColumn Header=" " CellTemplate="{StaticResource NumberTemplate}"/>
</GridView.Columns>
</GridView>
</ListView.View>
So my question is - how do I get this "PVNum" string in the code behind?
I did try this, though s is null - so I guess I'm off:
var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
var s = t.GetBindingExpression(TextBox.TextProperty);
Any suggestions?
It should be TextBlock.Text property:
var t = headerClicked.Column.CellTemplate.LoadContent() as TextBlock;
var s = t.GetBindingExpression(TextBlock.TextProperty);
string sourcePropertyName = s.ParentBinding.Path.Path;
A possible solution is to define an attached property for GridViewColumn:
public class GridViewColumnAttachedProperties
{
public static readonly DependencyProperty SortPropertyNameProperty = DependencyProperty.RegisterAttached(
"SortPropertyName", typeof(string), typeof(GridViewColumnAttachedProperties), new PropertyMetadata(default(string)));
public static void SetSortPropertyName(DependencyObject element, string value)
{
element.SetValue(SortPropertyNameProperty, value);
}
public static string GetSortPropertyName(DependencyObject element)
{
return (string) element.GetValue(SortPropertyNameProperty);
}
}
In XAML you set the attached properties to the Path used in the Binding inside the templates. Based on the example from the MSDN site:
<ListView x:Name='lv' Height="150" HorizontalAlignment="Center" VerticalAlignment="Center" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
<ListView.Resources>
<DataTemplate x:Key="YearTemplate">
<TextBlock Text="{Binding Year}" TextAlignment="Center" />
</DataTemplate>
<DataTemplate x:Key="MonthTemplate">
<TextBlock Text="{Binding Month}" TextAlignment="Center" />
</DataTemplate>
<DataTemplate x:Key="DayTemplate">
<TextBlock Text="{Binding Day}" TextAlignment="Center" />
</DataTemplate>
</ListView.Resources>
<ListView.ItemsSource>
<collections:ArrayList>
<system:DateTime>1993/1/1 12:22:02</system:DateTime>
<system:DateTime>1993/1/2 13:2:01</system:DateTime>
<system:DateTime>1997/1/3 2:1:6</system:DateTime>
<system:DateTime>1997/1/4 13:6:55</system:DateTime>
<system:DateTime>1999/2/1 12:22:02</system:DateTime>
<system:DateTime>1998/2/2 13:2:01</system:DateTime>
<system:DateTime>2000/2/3 2:1:6</system:DateTime>
<system:DateTime>2002/2/4 13:6:55</system:DateTime>
<system:DateTime>2001/3/1 12:22:02</system:DateTime>
<system:DateTime>2006/3/2 13:2:01</system:DateTime>
<system:DateTime>2004/3/3 2:1:6</system:DateTime>
<system:DateTime>2004/3/4 13:6:55</system:DateTime>
</collections:ArrayList>
</ListView.ItemsSource>
<ListView.View>
<GridView>
<GridViewColumn CellTemplate="{StaticResource YearTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Year" />
<GridViewColumn CellTemplate="{StaticResource MonthTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Month" />
<GridViewColumn CellTemplate="{StaticResource DayTemplate}" local:GridViewColumnAttachedProperties.SortPropertyName="Day" />
</GridView>
</ListView.View>
</ListView>
And in the Click event handler you can just retrieve the value of the attached property with string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;. Based on the MSDN example:
GridViewColumnHeader _lastHeaderClicked;
ListSortDirection _lastDirection = ListSortDirection.Ascending;
private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
if (headerClicked != null)
{
if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
{
ListSortDirection direction;
if (!ReferenceEquals(headerClicked, _lastHeaderClicked))
{
direction = ListSortDirection.Ascending;
}
else
{
if (_lastDirection == ListSortDirection.Ascending)
{
direction = ListSortDirection.Descending;
}
else
{
direction = ListSortDirection.Ascending;
}
}
string bindingName = headerClicked.Column.GetValue(GridViewColumnAttachedProperties.SortPropertyNameProperty) as string;
Sort(bindingName, direction);
if (direction == ListSortDirection.Ascending)
{
headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate;
}
else
{
headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate;
}
// Remove arrow from previously sorted header
if (_lastHeaderClicked != null && !ReferenceEquals(_lastHeaderClicked, headerClicked))
{
_lastHeaderClicked.Column.HeaderTemplate = null;
}
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
}
}
}
private void Sort(string sortBy, ListSortDirection direction)
{
ICollectionView dataView = CollectionViewSource.GetDefaultView(lv.ItemsSource);
dataView.SortDescriptions.Clear();
SortDescription sd = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sd);
dataView.Refresh();
}

mvvm:listview selected item fired when ItemsSource get value

I am new to MVVM I have scenario I have One textbox and One Listview .When textbox text(PONo) changed , the listview get populated with some data (PORecords) by filtering through the text.
My View is:
<TextBox Height="24"
VerticalAlignment="Top"
Width="119"
Text="{Binding Path=PONo,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
/>
<ListView Height="161"
ItemsSource="{Binding Path=PORecords}"
SelectedItem="{Binding Path=SelectedPO,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True"
Visibility="{Binding Path=PORecords,Converter={StaticResource ResourceKey=NullToVisibilityConverter}}"
Width="357">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=PurchaseOrderRefNo}"
Header="Order No"
Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Path=OrderDate, StringFormat=dd-MMM-yyyy}"
Header="Order Date"
Width="100" />
</GridView>
</ListView.View>
</ListView>
My ViewModel is:
private string _pONo;
public string PONo
{
get { return _pONo; }
set
{
if (value != "" && value!=null)
{
_pONo = value;
List<Tbl_PurchaseOrderMain> _lst = new List<Tbl_PurchaseOrderMain>();
_lst = new Tbl_PurchaseOrderMain().Select(" PurchaseOrderRefNo like '" + _pONo + "%'");
if (_lst.Count != 0)
{
PORecords = _lst;
}
else
{
PORecords = null;
}
}
else
{
PORecords = null;
}
RaisePropertyChanged("PONo");
}
}
private List<Tbl_PurchaseOrderMain> _pORecords;
public List<Tbl_PurchaseOrderMain> PORecords
{
get { return _pORecords; }
set
{
_pORecords = value;
RaisePropertyChanged("PORecords");
}
}
private Tbl_PurchaseOrderMain _selectedPO;
public Tbl_PurchaseOrderMain SelectedPO
{
get { return _selectedPO; }
set
{
_selectedPO = value;
if (SelectedPO != null)
{
PONo = SelectedPO.PurchaseOrderRefNo;
}
else
{
PONo = null;
}
RaisePropertyChanged("SelectedPO");
}
}
My problem is that when I enter text on textbox it will populate the listview (PORecords) with three Items.On that moment the selectedPO property is also fired then the textBox is filled the PONo but my listview then have only one Item the other two item gone .Actually I dont select any item on the Listview.I want to populate the textbox only when I select an Item from the listview whats wrong with my code any body have idea?

Converting Grid Content to a ListView or Other for use in MVVM Pattern

I have a 5 X 4 Grid (code below) which works as desired for the shape of my data. I recently discovered it is virtually impossible to pass a grid from the View Model to the View and bind it to another grid in XAML and still maintain the MVVM pattern - which is my goal.
The challenge here is that my presentation requires the children to be grouped in single cells with each having, 1 image, and two textblock UI elements.
DataTable, DataSet, GridView, List etc all seem to lack the ability to add multiple child elements to individual row/column cells for display. Unfortunately this is not just simply sticking an image in a column header.
Has anyone found another option for doing similar?
Thanks,
Glenn
Below is the sample grid and an image of the resulting view.
public void FormatGridCell()
{
Random random = new Random();
List<int> randomNumList = new List<int>();
for (int i = 0; i < 50; i++)
randomNumList.Add(random.Next(50));
List<string> columHeader = new List<string>();
columHeader.Add("Pitts");
columHeader.Add("Vans");
columHeader.Add("Lancair");
columHeader.Add("Epic");
List<string> rowHeader = new List<string>();
rowHeader.Add("NORTH");
rowHeader.Add("SOUTH");
rowHeader.Add("EAST");
rowHeader.Add("WEST");
rowHeader.Add("CANADA");
for (int x = 1; x < 5; x++)
{
var engineType= new TextBlock { Text = columHeader[x - 1] };
engineType.SetValue(Grid.RowProperty, 0);
engineType.SetValue(Grid.ColumnProperty, x);
engineType.HorizontalAlignment = HorizontalAlignment.Center;
this.airplaneGrid.Children.Add(engineType);
for (int r = 1; r < 6; r++)
{
var dealerService = new TextBlock { Text = rowHeader[r - 1] };
dealerService.SetValue(Grid.RowProperty, r);
dealerService.SetValue(Grid.ColumnProperty, 0);
dealerService.HorizontalAlignment = HorizontalAlignment.Center;
this.airplaneGrid.Children.Add(dealerService);
for (int i = 1; i < 6; i++)
{
// Bitmap path will be based on Type
var modelImage = new Image { Width = 20, Height = 20 };
var bitmapImage = new BitmapImage(new Uri(#"c:\personal\temp\dog.jpg"));
modelImage.Source = bitmapImage;
modelImage.SetValue(Grid.RowProperty, r);
modelImage.SetValue(Grid.ColumnProperty, i);
modelImage.HorizontalAlignment = HorizontalAlignment.Left;
modelImage.VerticalAlignment = VerticalAlignment.Top;
var mfgName = new TextBlock { Text = "Lancair IV" };
mfgName.SetValue(Grid.RowProperty, r);
mfgName.SetValue(Grid.ColumnProperty, i);
mfgName.HorizontalAlignment = HorizontalAlignment.Center;
var price = new TextBlock { Text = "$" + randomNumList[r + i] };
price.SetValue(Grid.RowProperty, r);
price.SetValue(Grid.ColumnProperty, i);
price.HorizontalAlignment = HorizontalAlignment.Left;
price.VerticalAlignment = VerticalAlignment.Center;
price.Margin = new Thickness(30, 0, 0, 0);
this.airplaneGrid.Children.Add(modelImage);
this.airplaneGrid.Children.Add(mfgName);
this.airplaneGrid.Children.Add(price);
}
}
}
}
This function is not mine. Sorry, forgot the named credit, but a fellow stackoverflow chap provided to this forum.
public static class RandomExtensions
{
public static int NextDouble(
Random random,
double minValue,
double maxValue)
{
return random.Next(10, 50);
}
}
Sorry, I'm too low on the totem pole to submit an image, but run it for a full understanding of the intended layout.
here is the XAML to support the above.
<Grid x:Name="airplaneGrid" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="175"/>
</Grid.ColumnDefinitions>
</Grid>
You could use another Grid (or stackpanel, or whatever type of panel) as the child element in each cell and then add the child elements to that panel
Ok. I placed your solution and mine side to side. It looks like this:
Admittedly, it requires a little bit more tweaking, but you get the main idea.
<ListView ItemsSource="{Binding}" Grid.Column="1">
<ListView.Resources>
<DataTemplate x:Key="CellContentTemplate">
<Border BorderBrush="LightGray" BorderThickness="1">
<DockPanel>
<Image Height="20" Width="20" Source="{Binding ImageSource}" Margin="2"
DockPanel.Dock="Left"/>
<StackPanel>
<TextBlock Text="{Binding Value, StringFormat='${0}'}" Margin="2"/>
<TextBlock Text="{Binding Name}" Margin="2"/>
</StackPanel>
</DockPanel>
</Border>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Pitts">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Pitts}" ContentTemplate="{StaticResource CellContentTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Vans">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Vans}" ContentTemplate="{StaticResource CellContentTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Lancair">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Lancair}" ContentTemplate="{StaticResource CellContentTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Epic">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Epic}" ContentTemplate="{StaticResource CellContentTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Code Behind (just random data):
Random random = new Random();
public GridSample() //Window Constructor
{
InitializeComponent();
var names = new[] {"NORTH","SOUTH","EAST","WEST"};
DataContext = names.Select(x => new GridViewModel()
{
Name = x,
Epic = CreateRandomCell(),
Lancair = CreateRandomCell(),
Pitts = CreateRandomCell(),
Vans = CreateRandomCell()
});
}
private CellViewModel CreateRandomCell()
{
return new CellViewModel
{
Name = "Cell" + random.Next(0, 100),
ImageSource = "/ChessPieces/BlackBishop.png",
Value = (decimal) random.Next(0, 100)
};
}
ViewModels:
public class GridViewModel
{
public string Name { get; set; }
public CellViewModel Pitts { get; set; }
public CellViewModel Vans { get; set; }
public CellViewModel Lancair { get; set; }
public CellViewModel Epic { get; set; }
}
public class CellViewModel
{
public string Name { get; set; }
public string ImageSource { get; set; }
public decimal Value { get; set; }
}
See? pure MVVM, clean, beautiful solution.

Alphabetically searching of records via accessing rest services in windows phone 7

I am trying to make Alphabetically searching of records via accessing rest services in windows phone 7.
Design page code..
<controls:PivotItem Header="buddies">
<toolkit:LongListSelector x:Name="BookList" Background="Transparent" IsFlatList="true"
GroupViewOpened="LongListSelector_GroupViewOpened"
GroupViewClosing="LongListSelector_GroupViewClosing">
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
<toolkit:LongListSelector.GroupItemTemplate>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource GroupBackground}}"
Width="99" Height="99" Margin="6" IsHitTestVisible="{Binding HasItems}">
<TextBlock Text="{Binding Title}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="48"
Margin="8,0,0,0"
Foreground="{Binding Converter={StaticResource GroupForeground}}"
VerticalAlignment="Bottom"/>
<Border.Projection>
<PlaneProjection RotationX="-60"/>
</Border.Projection>
</Border>
</DataTemplate>
</toolkit:LongListSelector.GroupItemTemplate>
<toolkit:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Border Background="Transparent" Margin="12,8,0,8">
<Border Background="{StaticResource PhoneAccentBrush}"
Padding="8,0,0,0" Width="62" Height="62"
HorizontalAlignment="Left">
<TextBlock Text="{Binding Title}"
Foreground="#FFFFFF"
FontSize="48"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"/>
</Border>
</Border>
</DataTemplate>
</toolkit:LongListSelector.GroupHeaderTemplate>
<toolkit:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Margin="12,8,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Width="110" Height="150" Source="{Binding ImageUrl}" VerticalAlignment="Top"/>
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<TextBlock Text="{Binding AutherName}" Style="{StaticResource PhoneTextLargeStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Margin="12,-12,12,6"/>
<TextBlock Text="{Binding Email}" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Title:" Style="{StaticResource PhoneTextSmallStyle}"/>
<TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Price:" Style="{StaticResource PhoneTextSmallStyle}"/>
<TextBlock Text="{Binding Price}" Style="{StaticResource PhoneTextSmallStyle}" FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</toolkit:LongListSelector.ItemTemplate>
</toolkit:LongListSelector>
</controls:PivotItem>
</controls:Pivot>
</Grid>
Here is my MainPage.xaml.cs page code
private LongListSelector currentSelector;
List<Person> objperson = null;
// Constructor
public MainPage()
{
InitializeComponent();
string Categoryid = "2";
WebClient proxy = new WebClient();
proxy.DownloadStringAsync(new Uri("http://localhost:3160/Service1.svc/GetListItemDetail/" + Categoryid));
proxy.DownloadStringCompleted += new DownloadStringCompletedEventHandler(proxy_DownloadStringCompleted);
}
void proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
XDocument doc = XDocument.Load(new StringReader(e.Result));
var CatList = (from item in doc.Descendants("ItemDetail")
select new Person
{
GenreName = item.Element("GenreName").Value.ToString(),
ItemID = Convert.ToInt32(item.Element("ItemID").Value),
CatID = Convert.ToInt32(item.Element("CatID").Value),
GenreID = Convert.ToInt32(item.Element("GenreID").Value),
AutherName = item.Element("AutherName").Value.ToString(),
Title = item.Element("Title").Value.ToString(),
Email = item.Element("Email").Value.ToString(),
Price = item.Element("Price").Value.ToString(),
Description = item.Element("Description").Value.ToString(),
ImageUrl = item.Element("ImageUrl").Value.ToString()
}).ToList();
objperson = new List<Person>();
objperson = CatList;
BookList.ItemsSource = CatList;
}
}
public List<Person> GetPersonListInfo()
{
List<Person> objp = new List<Person>();
objp = objperson;
return objp;
}
private void LongListSelector_GroupViewOpened(object sender, GroupViewOpenedEventArgs e)
{
//Hold a reference to the active long list selector.
currentSelector = sender as LongListSelector;
//Construct and begin a swivel animation to pop in the group view.
IEasingFunction quadraticEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };
Storyboard _swivelShow = new Storyboard();
ItemsControl groupItems = e.ItemsControl;
foreach (var item in groupItems.Items)
{
UIElement container = groupItems.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (container != null)
{
Border content = VisualTreeHelper.GetChild(container, 0) as Border;
if (content != null)
{
DoubleAnimationUsingKeyFrames showAnimation = new DoubleAnimationUsingKeyFrames();
EasingDoubleKeyFrame showKeyFrame1 = new EasingDoubleKeyFrame();
showKeyFrame1.KeyTime = TimeSpan.FromMilliseconds(0);
showKeyFrame1.Value = -60;
showKeyFrame1.EasingFunction = quadraticEase;
EasingDoubleKeyFrame showKeyFrame2 = new EasingDoubleKeyFrame();
showKeyFrame2.KeyTime = TimeSpan.FromMilliseconds(85);
showKeyFrame2.Value = 0;
showKeyFrame2.EasingFunction = quadraticEase;
showAnimation.KeyFrames.Add(showKeyFrame1);
showAnimation.KeyFrames.Add(showKeyFrame2);
Storyboard.SetTargetProperty(showAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
Storyboard.SetTarget(showAnimation, content.Projection);
_swivelShow.Children.Add(showAnimation);
}
}
}
_swivelShow.Begin();
}
private void LongListSelector_GroupViewClosing(object sender, GroupViewClosingEventArgs e)
{
//Cancelling automatic closing and scrolling to do it manually.
e.Cancel = true;
if (e.SelectedGroup != null)
{
currentSelector.ScrollToGroup(e.SelectedGroup);
}
//Dispatch the swivel animation for performance on the UI thread.
Dispatcher.BeginInvoke(() =>
{
//Construct and begin a swivel animation to pop out the group view.
IEasingFunction quadraticEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };
Storyboard _swivelHide = new Storyboard();
ItemsControl groupItems = e.ItemsControl;
foreach (var item in groupItems.Items)
{
UIElement container = groupItems.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (container != null)
{
Border content = VisualTreeHelper.GetChild(container, 0) as Border;
if (content != null)
{
DoubleAnimationUsingKeyFrames showAnimation = new DoubleAnimationUsingKeyFrames();
EasingDoubleKeyFrame showKeyFrame1 = new EasingDoubleKeyFrame();
showKeyFrame1.KeyTime = TimeSpan.FromMilliseconds(0);
showKeyFrame1.Value = 0;
showKeyFrame1.EasingFunction = quadraticEase;
EasingDoubleKeyFrame showKeyFrame2 = new EasingDoubleKeyFrame();
showKeyFrame2.KeyTime = TimeSpan.FromMilliseconds(125);
showKeyFrame2.Value = 90;
showKeyFrame2.EasingFunction = quadraticEase;
showAnimation.KeyFrames.Add(showKeyFrame1);
showAnimation.KeyFrames.Add(showKeyFrame2);
Storyboard.SetTargetProperty(showAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
Storyboard.SetTarget(showAnimation, content.Projection);
_swivelHide.Children.Add(showAnimation);
}
}
}
_swivelHide.Completed += _swivelHide_Completed;
_swivelHide.Begin();
});
}
private void _swivelHide_Completed(object sender, EventArgs e)
{
//Close group view.
if (currentSelector != null)
{
currentSelector.CloseGroupView();
currentSelector = null;
}
}
I am new to windows phone 7 application development, no idea about grouping of alphabets in Longlistselector. Please help me in that. Thanks in advance.
There is code I used once for grouping. As you can see, it's similar to Claus's:
public class YourList : ObservableCollection<ItemsInGroup>
{
private static readonly string Groups = "#abcdefghijklmnopqrstuvwxyz";
Dictionary<string, ItemsInGroup> groups = new Dictionary<string, ItemsInGroup>();
public YourList()
{
foreach (char c in Groups)
{
ItemsInGroup group = new ItemsInGroup(c.ToString());
this.Add(group);
groups[c.ToString()] = group;
}
}
public void AddItem(Item item)
{
string GroupKey = Item.GetSomeFieldKey(item);// a, b, etc.
for (int i = 0; i < groups[GroupKey].Count; i++)
{
if (Item.CompareBySomeField(item, groups[GroupKey][i]) < 0)
{
groups[Item.GetSomeFilesKey(item)].Insert(i, item);
return;
}
}
groups[GroupKey].Add(item);
}
}
.
public class ItemsInGroup : ObservableCollection<Item>, INotifyPropertyChanged
{
public ItemsInGroup(string category)
{
Key = category;
}
public string Key { get; set; }
public bool HasItems { get { return Count > 0; } }
//INotifyPropertyChanged implementation
}
Item must implement:
public static string GetSomeFieldKey(Item item)
and
public static int CompareBySomeFields(object obj1, object obj2)
Usage:
YourList list = new YourList();
foreach (var item in resultListFromService)
{
list.AddItem(item); // fill list with items
}
myList.ItemsSource = list; // bind to UI
Hope this helps better understand how it works
A super easy way to do it, is to use a specialized collection for the LongListSelector. I just so happen to have written one
Basically you would change your code to the following:
BookList.ItemsSource = new LongListCollection<Person, char>(CatList, x => x.Title[0]));
And you would get the alphabetic grouping on the first character of the Title property.
The only detail you need to be aware of, is that your Person class would need to implement IComparable<Person> to be ordered by the Title property (because you do want sorting, right?)
Simply done as:
public int Compare(Person other)
{
if (other == null)
return 1;
return this.Title.CompareTo(other.Title);
}

Categories