I am using the _wordItems as the longlistselector's itemsource in order to dynamically delete items in longlistSelector
private ObservableCollection<Group<WordItem>> _wordItems = new ObservableCollection<Group<WordItem>>();
The Group class is defined as:
public class Group<T> : ObservableCollection<T>
{
public Group(string name, IEnumerable<T> items)
{
this.Key = name;
foreach (T item in items)
{
this.Add(item);
}
}
public override bool Equals(object obj)
{
Group<T> that = obj as Group<T>;
return (that != null) && (this.Key.Equals(that.Key));
}
public string Key
{
get;
set;
}
}
and the WordItem class is defined as:
[Table]
public class WordItem //:INotifyPropertyChanged,INotifyPropertyChanging
{
private int _wordItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int WordItemId
{
get
{
return _wordItemId;
}
set
{
if (_wordItemId != value)
{
_wordItemId = value;
}
}
}
private string _word;
[Column(CanBeNull=false)]
public string Word
{
get
{
return _word;
}
set
{
if (_word != value)
{
_word = value;
}
}
}
private string _wordExplains;
[Column]
public string WordExplains
{
get
{
return _wordExplains;
}
set
{
if (_wordExplains != value)
{
_wordExplains = value;
}
}
}
}
when I use the code _wordItems[1].RemoveAt(1);, the _wordItems has been modified, and the longlistselector in the screen has also deleted certain item. But the problem is that when I call _wordItems[1].RemoveAt(1);, the longlistselector just deleted the _wordItems[1][0] item. When I call _wordItems[1].RemoveAt(0);, it just deleted the header of the second group and combined the items in _worditems[1] with the _wordItem[0].
The definition of longlistselector:
<toolkit:LongListSelector x:Name="WordsGroup" Background="Transparent"
Margin="12,0,12,73" ItemTemplate="{StaticResource WordItemTemplate}"
GroupHeaderTemplate="{StaticResource YoudaoGroupHeaderTemplate}"
GroupItemTemplate="{StaticResource YoudaoGroupItemTemplate}"
SelectionChanged="WordsGroup_SelectionChanged"
>
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
</toolkit:LongListSelector>
The datatemplate is as:
<DataTemplate x:Key="WordItemTemplate">
<Border BorderBrush="Gray" BorderThickness="0,0,0,0" Margin="0,3,0,5">
<StackPanel >
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu Opened="ContextMenu_Opened" >
<toolkit:MenuItem Header="delete this word" Click="DelectWord_Click"/>
<toolkit:MenuItem Header="share this word" Click="SMSShare_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding WordItemId}" Style="{StaticResource PhoneTextNormalStyle}" Visibility="Collapsed"/>
<TextBlock Text="{Binding Word}" Style="{StaticResource PhoneTextNormalStyle}" FontSize="25" Foreground="Black" FontWeight="Bold"/>
<TextBlock Text="{Binding WordExplains}" Style="{StaticResource PhoneTextNormalStyle}" Foreground="Black" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="YoudaoGroupHeaderTemplate">
<Border Background="#1BA1E2" Margin="0">
<TextBlock Text="{Binding Key}" FontSize="30" Margin="12,0,0,0" Foreground="Black" />
</Border>
</DataTemplate>
<DataTemplate x:Key="YoudaoGroupItemTemplate" >
<Border Background="#1BA1E2" Width="99" Height="99" Margin="6">
<TextBlock Text="{Binding Key}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="40" Foreground="{StaticResource PhoneForegroundBrush}"/>
</Border>
</DataTemplate>
Thx in advance.
ps. I am using the linq as
var wordBy4sLetter = from word in wordList
group word by word.Word.ToCharArray()[0].ToString() into s
orderby s.Key
select new Group<WordItem>(s.Key, s);
this._wordItems = wordBy4sLetter.ToObservableCollection();
this.WordsGroup.ItemsSource = this._wordItems;
I think you need another ObservableCollection. Take a look at the accepted answer for this question. Group Listbox for Windows Phone 7?
I have modified the code there and created new Add/Remove methods that will create a group if not there for an add, and remove the group if it's empty on a remove.
Related
I know that there were many questions about this and I searched a lot and tried everything which I found about this but I can't get it working.
Simply put, for some reason I'm unable to show an image inside a ListView item template.
So I have this ItemViewModel class:
public class ItemViewModel : BaseViewModel, IItemViewModel
{
public ItemViewModel()
{
if (dalInterface == null)
{
dalInterface = ApplicationContext.Container.Resolve<IDalInterface>();
}
if (eventCenter == null)
{
eventCenter = ApplicationContext.Container.Resolve<IEventCenter>();
}
SaveCommand = new Command(SaveChanges, true);
DeleteCommand = new Command(RemoveItem, true);
AddNewItemCommand = new Command(AddNewItem, true);
}
public ICommand SaveCommand { get; set; }
public ICommand DeleteCommand { get; set; }
public ICommand AddNewItemCommand { get; set; }
private Item data;
public int ID { get; private set; }
private string title;
public string Title
{
get { return title; }
set
{
title = value;
NotifyPropertyChanged("Title");
}
}
private string author;
public string Author
{
get { return author; }
set
{
author = value;
NotifyPropertyChanged("Author");
}
}
private string shortDescription;
public string ShortDescription
{
get { return shortDescription; }
set
{
shortDescription = value;
NotifyPropertyChanged("ShortDescription");
}
}
private string buyPrice;
public string BuyPrice
{
get { return buyPrice; }
set
{
buyPrice = value;
NotifyPropertyChanged("BuyPrice");
}
}
private string borrowPrice;
public string BorrowPrice
{
get { return borrowPrice; }
set
{
borrowPrice = value;
NotifyPropertyChanged("BorrowPrice");
}
}
private int quantity;
public int Quantity
{
get { return quantity; }
set
{
quantity = value;
NotifyPropertyChanged("Quantity");
}
}
private string detailedDescription;
public string DetailedDescription
{
get { return detailedDescription; }
set
{
detailedDescription = value;
NotifyPropertyChanged("DetailedDescription");
}
}
private string imagePath;
public string ImagePath
{
get { return imagePath; }
set
{
imagePath = value;
NotifyPropertyChanged("ImagePath");
}
}
private Image image;
public Image Image
{
get { return image; }
set
{
image = value;
NotifyPropertyChanged("Image");
}
}
public void SetData(Item item)
{
data = item;
ID = data.ID;
Author = data.Author;
Title = data.Title;
Quantity = data.Quantity;
ShortDescription = data.ShortDescription;
DetailedDescription = data.DetailedDescription;
BuyPrice = data.BuyPrice;
BorrowPrice = data.BorrowPrice;
Image = GetImage(data.ImagePath);
}
private Image GetImage(string imagePath)
{
var imageUri = new Uri(imagePath, UriKind.RelativeOrAbsolute);
var bitmapImage = new BitmapImage(imageUri);
var image = new Image
{
Source = bitmapImage
};
return Image;
}
private void SaveChanges()
{
UpdateChanges(data);
dalInterface.UpdateItem(data);
}
private void RemoveItem()
{
dalInterface.RemoveItem(data);
}
private void AddNewItem()
{
var newItem = new Item();
if (AllDataCorrect())
{
UpdateChanges(newItem);
dalInterface.AddNewItem(newItem);
eventCenter.Publish(new AddItemEventArgs { OperationSuccess = true });
}
else
{
eventCenter.Publish(new AddItemEventArgs { OperationSuccess = false });
}
}
private void UpdateChanges(Item itemToUpdate)
{
itemToUpdate.Author = Author;
itemToUpdate.Title = Title;
itemToUpdate.BorrowPrice = BorrowPrice;
itemToUpdate.BuyPrice = BuyPrice;
itemToUpdate.DetailedDescription = DetailedDescription;
itemToUpdate.ShortDescription = ShortDescription;
itemToUpdate.Quantity = Quantity;
itemToUpdate.ImagePath = ImagePath;
}
private bool AllDataCorrect()
{
float val = -1.0F;
float.TryParse(BuyPrice, out val);
if (val <= 0.0F)
{
return false;
}
float.TryParse(BorrowPrice, out val);
if (val <= 0.0F)
{
return false;
}
if ((ShortDescription == string.Empty) ||
(DetailedDescription == string.Empty) ||
(Author == string.Empty) ||
(Title == string.Empty)
)
{
return false;
}
if (Quantity <= 0)
{
return false;
}
return true;
}
public void Clear()
{
Author = string.Empty;
Title = string.Empty;
ImagePath = string.Empty;
ShortDescription = string.Empty;
DetailedDescription = string.Empty;
BuyPrice = string.Empty;
BorrowPrice = string.Empty;
Quantity = 0;
}
}
And for this class I have the following user control:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="4"
Style="{StaticResource ImageBorderStyle}">
<Image Source="{Binding Image, Mode=TwoWay}"
MinWidth="80"
MinHeight="80"
Stretch="UniformToFill"/>
</Border>
<Border Grid.Row="0"
Grid.Column="1"
Style="{StaticResource BaseBorderStyle}">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Wiki"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="1"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="Auto"
Text="{Binding ShortDescription}"/>
</Border>
</Grid>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Grid.Column="1"
Style="{StaticResource BaseBorderStyle}"
HorizontalAlignment="Left"
Width="100">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="About"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="1"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="Auto"
Text="{Binding DetailedDescription}"/>
</Border>
</Grid>
</Grid>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Title"
TextAlignment="Center"
HorizontalAlignment="Stretch"/>
</Border>
<Border Grid.Row="1"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
Text="{Binding Title}"/>
</Border>
<Border Grid.Row="2"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Author"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="3"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
Text="{Binding Author}"/>
</Border>
<Border Grid.Row="4"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Quantity"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="5"
Grid.Column="0"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
Text="{Binding Quantity}"/>
</Border>
<Border Grid.Row="0"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Buy Price"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="1"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
Text="{Binding BuyPrice}"/>
</Border>
<Border Grid.Row="2"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource BaseTextBlockStyle}"
Text="Borrow Price"
TextAlignment="Center"/>
</Border>
<Border Grid.Row="3"
Grid.Column="1"
Style="{StaticResource DetailsBorderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox Style="{StaticResource DataTextBoxStyle}"
HorizontalAlignment="Stretch"
Text="{Binding BorrowPrice}"/>
</Border>
<Button Grid.Row="5"
Grid.Column="1"
Style="{StaticResource SaveButtonStyle}"/>
<Button Grid.Row="5"
Grid.Column="1"
Style="{StaticResource RemoveButtonStyle}"
HorizontalAlignment="Right"/>
</Grid>
</Grid>
Using this I want to show into a page, inside a list view, based on an observable collection, loaded from a database some items.
The page view model is the follow:
public class ManageItemsViewModel : BaseViewModel, IManageItemsViewModel
{
public ManageItemsViewModel()
{
if(dalInterface == null)
{
dalInterface = ApplicationContext.Container.Resolve<IDalInterface>();
}
if(eventCenter == null)
{
eventCenter = ApplicationContext.Container.Resolve<IEventCenter>();
}
Items = new ObservableCollection<ItemViewModel>();
}
public ObservableCollection<ItemViewModel> Items { get; set; }
public void Refresh()
{
var dalItems = dalInterface.GetAllItems();
foreach(Item item in dalItems)
{
var vm = Items.Where(v => v.ID.Equals(item.ID));
if(vm.Equals(null))
{
var newItemVm = (ItemViewModel)ApplicationContext.Container.Resolve<IItemViewModel>();
newItemVm.SetData(item);
Items.Add(newItemVm);
}
}
NotifyPropertyChanged("Items");
}
public void LoadData()
{
if(Items.Count == 0)
{
var dalItems = dalInterface.GetAllItems();
foreach(Item item in dalItems)
{
var newItemVm = (ItemViewModel)ApplicationContext.Container.Resolve<IItemViewModel>();
newItemVm.SetData(item);
Items.Add(newItemVm);
}
NotifyPropertyChanged("Items");
}
else
{
Refresh();
}
}
}
And the page view is the follow:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Margin="2"
Style="{StaticResource AddButtonStyle}"
Click="GoToAddNewItem"/>
<Button Grid.Row="0"
Margin="2"
HorizontalAlignment="Right"
Style="{StaticResource CloseButtonStyle}"
Click="GoToItems"/>
<ListView Grid.Row="1"
ItemsSource="{Binding Items, Mode=TwoWay}"
Margin="5">
<ListView.ItemTemplate>
<DataTemplate>
<templates:EditableItem/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
That page should be like (at the moment I only have one item in DB for tests):
The problem which I facing now is that I cannot see the Image inside this item template, although all the other properties are correctly shown inside the item template.
I've tried to use the image path as I get it from DB and bind into item xaml the source path property to this, also I tried to have an ImageSource or BitmapImage property inside item VM to have the xaml image source bound to this property but without any success so far.
After reading many questions about and trying again and again without success I'm here...
Any hints about what I'm doing wrong?
Many thanks!
(P.S. The app which I'm working to is an UWP app, maybe it matters...)
You can't use an Image control as the value of the Source property of another Image control.
Use an ImageSource instead:
private ImageSource image;
public ImageSource Image
{
get { return image; }
set
{
image = value;
NotifyPropertyChanged("Image");
}
}
And change the GetImage method to:
private ImageSource GetImage(string imagePath)
{
return new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute));
}
That said, you could simply drop the Image property and bind directly to ImagePath. Built-in type conversion will automatically convert from a path string to ImageSource.
<Image Source="{Binding ImagePath}"/>
Note also that Mode=TwoWay makes no sense for this Binding.
As I searched again and again about this problem and tried lots of suggested solutions I finally found a solution which is suitable for me and solves this problem.
I implemented a little demo to show how exactly is working. The UWP app is not constraint to interact with the pictures folder only. The images can be loaded from an arbitrary folder on disk.
Hope that this will help others to.
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
PickFileCommand = new ActionCommand(PickFile, true);
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand PickFileCommand { get; set; }
private BitmapImage imageSrc;
public BitmapImage ImageSrc
{
get { return imageSrc; }
set
{
imageSrc = value;
NotifyPropertyChanged("ImgSource");
}
}
private async void PickFile()
{
var filePicker = new FileOpenPicker
{
SuggestedStartLocation = PickerLocationId.PicturesLibrary
};
filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".png");
StorageFile file = await filePicker.PickSingleFileAsync();
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
var bitmap = new BitmapImage
{
UriSource = new Uri(file.Path, UriKind.Absolute)
};
await bitmap.SetSourceAsync(stream);
ImageSrc = bitmap;
}
}
protected void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
Now, the trick which solved the image problem is in View code behind class.
public sealed partial class MainPage : Page
{
private ViewModel dataContext;
public MainPage()
{
this.InitializeComponent();
dataContext = new ViewModel();
DataContext = dataContext;
}
**private void PageLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModel dc)
{
dc.PropertyChanged += Dc_PropertyChanged;
}
}
private void Dc_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if(e.PropertyName.Equals("ImgSource"))
{
if (DataContext is ViewModel dc)
{
ShowImage.Source = dc.ImageSrc;
}
}
}**
}
What was needed it was that the source of the Image UI element to be set explicitly. I made this by subscribing to the PropertyChanged event from ViewModel and set the image source.
I am developing a WP7 app that contains a LongListSelector. Within the ItemTemplate there is a ListPicker. I select a value from the ListPicker for the first item in the LongListSelector, then select a value from the ListPicker for the 2nd item. If I then scroll down the page and back to the top again, the value I selected in the ListPicker for the 1st item will be reset (SelectedIndex=0).
I have put code in the Link and Unlink events of the LongListSelector to write to the output window and I have found that when the 1st item unlinks (due to scrolling down the page), the ListPicker value is what I selected but as soon as the link event fires (due to scrolling back up the page) for the 1st item the value is reset.
Im using ObserableCollection and implement the INPC interface for my objects and the ViewModel updates when the ListPicker selection is changed.
How can I ensure that the value in the ListPickers are retaining during scrolling of the LongListSelector?
MainPage.xaml
<phone:PhoneApplicationPage
x:Class="LongListSelector.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="5000"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit">
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Name="occurrenceItemTemplate">
<Grid>
<StackPanel Orientation="Vertical" Margin="5,0,0,0" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="tbkEventDateTime" Grid.Row="0" Grid.Column="0"
Text="{Binding ItemNumber}"
Style="{StaticResource PhoneTextSmallStyle}" />
<!--<TextBox Name="txtEventDateTime" Grid.Row="1" Grid.Column="0"
Text="{Binding Result}" />-->
<toolkit:ListPicker Name="lpkResult" Margin="12,0,12,12"
Grid.Row="1" Grid.Column="0"
ItemsSource="{Binding TestItemResultList, Mode=OneTime}"
SelectedIndex="{Binding Result, Mode=TwoWay}"
CacheMode="BitmapCache">
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" VerticalAlignment="Stretch">
<toolkit:LongListSelector x:Name="lstOutstandingOccurrences"
Margin="0,12,0,0" Padding="0,0,0,24"
ItemTemplate="{StaticResource occurrenceItemTemplate}"
ItemsSource="{Binding TestItemCollection, Mode=TwoWay}"
IsFlatList="True" ShowListHeader="False" >
</toolkit:LongListSelector>
</Grid>
</Grid>
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
private TestItemViewModel _vm;
public TestItemViewModel ViewModel
{
get
{
if (_vm == null)
_vm = new TestItemViewModel();
return _vm;
}
private set
{
_vm = value;
}
}
// Constructor
public MainPage()
{
InitializeComponent();
this.lstOutstandingOccurrences.Link += new EventHandler<LinkUnlinkEventArgs>(lstOutstandingOccurrences_Link);
this.lstOutstandingOccurrences.Unlink += new EventHandler<LinkUnlinkEventArgs>(lstOutstandingOccurrences_Unlink);
this.DataContext = this.ViewModel;
}
void lstOutstandingOccurrences_Link(object sender, LinkUnlinkEventArgs e)
{
var item = e.ContentPresenter.Content as TestItem;
Debug.WriteLine("Link event for ItemNumber {0} = {1}", item.ItemNumber, item.Result);
}
void lstOutstandingOccurrences_Unlink(object sender, LinkUnlinkEventArgs e)
{
var item = e.ContentPresenter.Content as TestItem;
Debug.WriteLine("Unlink event for ItemNumber {0} = {1}", item.ItemNumber, item.Result);
}
}
TestItemViewModel.cs
public class TestItemViewModel : BaseINPC
{
public ObservableCollection<TestItem> TestItemCollection
{
get;
private set;
}
// Constructor
public TestItemViewModel()
{
this.TestItemCollection = new ObservableCollection<TestItem>();
CreateTestData(20);
}
public void CreateTestData(int totalItems)
{
//create test data for long list selector.
for (int i = 1; i <= totalItems; i++)
{
this.TestItemCollection.Add(new TestItem(i, 0));
}
}
}
Models
public class ListHelperListItem
{
public int Value { get; set; }
public string Text { get; set; }
}
public class TestItem : BaseINPC
{
public TestItem(int ItemNumber, int Result)
{
this.ItemNumber = ItemNumber;
this.Result = Result;
}
public int ItemNumber { get; set; }
private int _Result;
public int Result
{
get
{
return _Result;
}
set
{
//if statement is for debugging purposes only.
if (this.ItemNumber == 1)
{
_Result = value;
}
_Result = value;
RaisePropertyChanged("Result");
}
}
private List<ListHelperListItem> _TestItemResultList;
public List<ListHelperListItem> TestItemResultList
{
get
{
_TestItemResultList = new List<ListHelperListItem>();
_TestItemResultList.Add(new ListHelperListItem { Value = 0, Text = " " });
_TestItemResultList.Add(new ListHelperListItem { Value = 1, Text = "Yes" });
_TestItemResultList.Add(new ListHelperListItem { Value = 2, Text = "No" });
_TestItemResultList.Add(new ListHelperListItem { Value = 3, Text = "Ignore" });
return _TestItemResultList;
}
}
}
Thanks for your help!
I have a pivot control, the items are binded from a list, I want to make the pivot header look like a page number, look like this : (1/20) (2/20) (3/20) .... This is my xaml:
<Grid x:Name="LayoutRoot">
<Grid.Background>
<ImageBrush ImageSource="/Images/PivotBackground.png"/>
</Grid.Background>
<!--Pivot Control-->
<controls:Pivot x:Name="newsPivot" ItemsSource="{Binding LatestArticles}" Margin="0,68,0,0">
<!--Pivot item one-->
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="1" FontSize="30" Foreground="White" TextWrapping="Wrap"/>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<Grid>
<StackPanel>
<TextBlock Text="{Binding title}" FontSize="30" Foreground="Black" TextWrapping="Wrap"
Grid.Row="1"
Grid.Column="0"
Width="425"
Margin="10,0,0,0"/>
</StackPanel>
<StackPanel>
<Image delay:LowProfileImageLoader.UriSource="{Binding thumbnail, StringFormat='http://digitaledition.philstar.com/newsrepository/newsarticles/thumbs/images/\{0\}'}"
Margin="18,100,0,0"
Grid.Column="0"
Grid.Row="2"
HorizontalAlignment="Left"
Width="150"
Height="175"
Stretch="UniformToFill" />
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding author, StringFormat='By \{0\}'}" TextWrapping="Wrap" FontSize="22"
Grid.Column="1"
Width="220"
Foreground="Gray"
Margin="120,135,0,0"/>
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding dateFormatted}" TextWrapping="Wrap" FontSize="20"
Grid.Column="1"
Width="240"
Foreground="Gray"
Margin="140,210,0,0"/>
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding content}" TextWrapping="Wrap" FontSize="24"
Grid.Column="1"
Width="425"
Foreground="Black"
Margin="10,325,0,0"/>
</StackPanel>
</Grid>
</ScrollViewer>
</DataTemplate>
</controls:Pivot.ItemTemplate>
<!--Pivot item two-->
</controls:Pivot>
</Grid>
Spent hours of searching on google but no solution found. Please someone help me with my project. thanks in advance!
Code behind Xaml:
public NewsPivot()
{
InitializeComponent();
var y = new WebClient();
Observable
.FromEvent<DownloadStringCompletedEventArgs>(y, "DownloadStringCompleted")
.Subscribe(r =>
{
var des =
JsonConvert.DeserializeObject<List<LatestArticles>>(r.EventArgs.Result);
newsPivot.ItemsSource = des.Where(s=> s.category_id == "1");
});
y.DownloadStringAsync(
new Uri("http://sample.json.com/mobile/articles?"));
}
LatestArticle.cs :
public class LatestArticles
{
public string id { get; set; }
public string title { get; set; }
public string thumbnail { get; set; }
public string hits { get; set; }
public string thumbCaption { get; set; }
public string category_id { get; set; }
public string dateFormatted { get; set; }
public string author { get; set; }
}
You would have to Bind the Text of the Header to a property on your Articles object. This propery would be the page index of the article.
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding PageNumber}" FontSize="30" Foreground="White" TextWrapping="Wrap"/>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
You would then need to set the page number of the Article when it is added to the LatestArticles collection.
LatestArticles.Add(article);
article.PageNumber = LatestArticles.Count +1;
Another option is to use a value converter. This option would require you to have access to the LatestArticles somehow.
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource PageNumberConverter}}" FontSize="30" Foreground="White" TextWrapping="Wrap"/>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
The ValueConverter is very simple
public class PageNumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Assumes that the App.xaml.cs class has a static ViewModel property
return App.ViewModel.LatestArticles.IndexOf(value) + 1;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
So, I have a code:
<tool:LongListSelector x:Name="citiesListGropus" Background="Transparent"
ItemTemplate="{StaticResource citiesItemTemplate}"
GroupHeaderTemplate="{StaticResource groupHeaderTemplate}"
GroupItemTemplate="{StaticResource groupItemTemplate}" Height="468" Margin="0,68,0,0">
<tool:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<tool:WrapPanel/>
</ItemsPanelTemplate>
</tool:LongListSelector.GroupItemsPanel>
</tool:LongListSelector>
And have a DataTemplate:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
How can I change a property Visibility of Border in DataTemplate ? I want to hide DataTemplate. But I can't bind my data to a property such as TextBlock Text="{Binding Title}", because I make binding data once, then I need to change some properties after data binding.
Any Ideas?
UPDATE 1
So, my main goal is filter the list of cities. I want to filter them by name.
My algorithm:
1) I get data from WebService.
2) Load my ViewModel
if (!App.CitiesViewModel.IsDataLoaded)
{
App.CitiesViewModel.LoadData(serviceResponse.Result);
}
3) Group the cities by name. My code like this code.
This is important, especially for LongListSeletstor I have to use templates.
Ok, my data ready. Now I do not need a web service.
<!-- The template for city items -->
<DataTemplate x:Key="citiesItemTemplate">
<StackPanel Name="PlacePanel"
Orientation="Horizontal" Margin="0,0,0,17"
Tag="{Binding Id}" Visibility="{Binding IsVisibility}">
<Image Height="75" Width="75" HorizontalAlignment="Left" Margin="12,0,9,0" Name="Image" Stretch="Fill" VerticalAlignment="Top" Source="{Binding Image}"/>
<StackPanel Width="311">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
I have TextBox, when I type name of a city - unnecessary cities hide. I can use data binding and INotifyPropertyChanged, so I can hide cities.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox name = (TextBox)sender;
foreach(var place in App.CitiesViewModel.Items
.Where(city => (city.Name.Contains(name.Text)) && (city.IsShow == true)))
{
city.IsVisibility = Visibility.Visible;
}
foreach (var city in App.CitiesViewModel.Items
.Where(city => !city.Name.Contains(name.Text)))
{
city.IsVisibility = Visibility.Collapsed;
}
}
But I have some problems, I can't hide this DataTemplate when I search cities:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
When I type name of a cities I want hide GroupHeaderTemplate. When TextBox lost focus show GroupHeaderTemplate.
I borrowed this picture here.
Update 2
My mistake was that I did not use PropertyChangedEventHandler. After adding this to GroupCity property and implementing an interface INotifyPropertyChanged I can change property Data Template after data binding.
private IList<Group<City>> citiesCollectionGroup;
var cityByName = from city in App.ViewModel.Items
group city by Convert.ToString(City.Name[0]).ToLower()
into c orderby c.Key select new
GroupCity<CitiesViewModel>(Convert.ToString(c.Key[0]).ToLower(), c);
citiesCollectionGroup = cityByName.ToList();
this.citiesListGropus.ItemsSource = citiesCollectionGroup;
public class GroupCity<T> : IEnumerable<T>, INotifyPropertyChanged
{
public GroupCity(string name, IEnumerable<T> items)
{
this.Title = name;
this.IsVisibility = Visibility.Visible;
this.Items = new List<T>(items);
}
public override bool Equals(object obj)
{
GroupCity<T> that = obj as GroupCity<T>;
return (that != null) && (this.Title.Equals(that.Title));
}
public string Title
{
get;
set;
}
private Visibility _isVisibility;
public Visibility IsVisibility
{
get
{
return _isVisibility;
}
set
{
_isVisibility = value;
NotifyPropertyChanged("IsVisibility");
}
}
public IList<T> Items
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return this.Items.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.Items.GetEnumerator();
}
#endregion
}
Xaml code:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName" Visibility="{Binding IsVisibility}">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
Now we can change Visibility groupHeaderTemplate.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
foreach (GroupCity<CitiesViewModel> city in citiesCollectionGroup)
{
city.IsVisibility = Visibility.Collapsed;
}
//
}
private void SearchText_LostFocus(object sender, RoutedEventArgs e)
{
foreach (GroupCity<CitiesViewModel> city in citiesCollectionGroup)
{
city.IsVisibility = Visibility.Visible;
}
//
}
You can write your own simple DataTemplateSelector to do this. Check this out for more information.
With "How can I change a property Visibility of Border in DataTemplate ? I want to hide DataTemplate. " I understand that you want to change the visibility of an item based on a property, see example below.
(If the code below isn't quite the solution you are looking for please provide some more information about what you are trying to achieve. Re-reading your question and the comments I got on this example I doubt this is what you want to do, but I don't want to guess so I'm simply answering my interpretation of your question).
With bindings you can:
Bind the visibility property directly to a a property of type Visibility (example with listbox and Person1)
Bind the Visibility property to a boolean property, and use a converter to convert that to the Visibility type (listbox2 and Person2 + BoolToVis class).
There are more ways, but this are the two most simple to implement in my opinion.ยจ
result of code below:
View:
<phone:PhoneApplicationPage
x:Class="VisibilityWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
xmlns:VisibilityWP="clr-namespace:VisibilityWP"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<VisibilityWP:BoolToVis x:Key="BooleanToVisibilityConverter" />
</Grid.Resources>
<StackPanel>
<ListBox x:Name="listBox" Height="300">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="200" Visibility="{Binding Visibility}" Background="Blue">
<TextBlock Text="{Binding Name}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="listBox2" Height="300">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="200" Visibility="{Binding ShowBorder, Converter={StaticResource BooleanToVisibilityConverter}}" Background="Red">
<TextBlock Text="{Binding Name}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Grid>
Code behind:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace VisibilityWP
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
DataContext = this;
listBox.ItemsSource = new List<Person1>
{
new Person1 {Name = "Iris", Visibility = Visibility.Visible},
new Person1 {Name = "Somebody", Visibility = Visibility.Collapsed},
new Person1 {Name = "Peter", Visibility = Visibility.Visible},
};
listBox2.ItemsSource = new List<Person2>
{
new Person2 {Name = "Iris", ShowBorder = true},
new Person2 {Name = "Mia", ShowBorder = true},
new Person2 {Name = "Somebody", ShowBorder = false}
};
}
}
public class Person1
{
public string Name { get; set; }
public Visibility Visibility { get; set; }
}
public class Person2
{
public string Name { get; set; }
public bool ShowBorder { get; set; }
}
public sealed class BoolToVis : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value is Visibility && (Visibility)value == Visibility.Visible;
}
}
}
I have a listbox that I'm doing some databinding. As you can see I have some images associated with the data that I'm displaying... Everything is working great, except that when I change themes I need to change my image to the black images. I can't seem to figure out how to change the images when they are bound like this.
Any ideas?
<ListBox x:Name="lbPharm" ItemsSource="{Binding col}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
<TextBlock FontFamily="Segoe WP Semibold" FontWeight="Bold" FontSize="30" VerticalAlignment="Top" Margin="20,10">*</TextBlock>
<StackPanel>
<TextBlock x:Name="ItemText" Text="{Binding name}" FontSize="{StaticResource PhoneFontSizeLarge}"/>
<TextBlock x:Name="ItemNumber" Text="{Binding number}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
</StackPanel>
<Image Source="Images/phone.png" Margin="20,0" x:Name="phone" Visibility="Visible">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap_Phone"/>
</toolkit:GestureService.GestureListener>
</Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should create a binding for the image source instead of setting it explicitly in XAML.
<ListBox x:Name="lbPharm" ItemsSource="{Binding col}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
<TextBlock FontFamily="Segoe WP Semibold" FontWeight="Bold" FontSize="30" VerticalAlignment="Top" Margin="20,10">*</TextBlock>
<StackPanel>
<TextBlock x:Name="ItemText" Text="{Binding name}" FontSize="{StaticResource PhoneFontSizeLarge}"/>
<TextBlock x:Name="ItemNumber" Text="{Binding number}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
</StackPanel>
<!-- Image source is bound to a property -->
<Image Source="{Binding ImageSource}" Margin="20,0" x:Name="phone" Visibility="Visible">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap_Phone"/>
</toolkit:GestureService.GestureListener>
</Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, just update the property in your view model as needed, as long as the class containing the property implements INotifyPropertyChanged the new image will show up in your ListBox.
The ImageSource property may have to be a BitmapImage instead of a string. XAML must use a converter to convert your path string when it is used as a literal but I think it doesn't do this if you use a binding. Or you could use your own converter. Either way, construct a BitmapImage as follows:
new BitmapImage( new Uri( "/path/to/image.png", UriKind.Relative ) )
EDIT
Adding an example:
<DataTemplate x:Key="LongListSelectorItemTemplate">
<StackPanel VerticalAlignment="Top"
Orientation="Horizontal">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="OnTap" />
</toolkit:GestureService.GestureListener>
<Image Source="{Binding ImageSource}"
MinHeight="32"
MinWidth="32"
MaxHeight="48"
MaxWidth="48" />
<StackPanel>
<TextBlock Text="{Binding Name}"
Style="{StaticResource PhoneTextExtraLargeStyle}"
Margin="12,10,12,0" />
<TextBlock Text="{Binding Parent}"
Foreground="{StaticResource PhoneAccentBrush}"
Style="{StaticResource PhoneTextSubtleStyle}"
Margin="24,0,12,10" />
</StackPanel>
</StackPanel>
</DataTemplate>
Corresponding view model:
public class Item : INotifyPropertyChanged
{
#region Private Members
private string _name = null;
private string _imageSource = null;
private string _parent = null;
#endregion
public string Name
{
get
{
return _name;
}
set
{
if( value != _name ) {
_name = value;
NotifyPropertyChanged( "Name" );
}
}
}
public string Parent
{
get
{
return _parent;
}
set
{
if( value != _parent ) {
_parent = value;
NotifyPropertyChanged( "Parent" );
}
}
}
public string ImageSource
{
get
{
return _imageSource;
}
set
{
if( value != _imageSource ) {
_imageSource = value;
NotifyPropertyChanged( "ImageSource" );
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged( String propertyName )
{
PropertyChangedEventHandler handler = PropertyChanged;
if( null != handler ) {
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
}
#endregion
}
This is code from a project I'm working on, it is similar to your case except I'm displaying the image with a LongListSelector instead of a ListBox. And it looks like I mislead you earlier about not being able to use a string directly for the image source, I'm doing exactly that and it works. Sorry about that.