I have a Pivot element that has a header template and an itemtemplate with a listbox which also has a itemtemplate. The header template is bound to a list of "DOWS" which i create via code. This works fine. Each DOW has a entityset TDs and i want to bind the listbox itemtemplate to this source. Once i bound it, deleting an item updates the ui fine but adding an item doesn't update the ui.
the entityset is based off of the "Local database with mvvm" example here:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh286405(v=vs.105).aspx
I've researched for a few days and cant find anything helpful. some solutions i found where to wrap the entityset in a observable collection but that didnt seem to work. Another one was to use BindingLists, but entitySets dont have "ToBindingList()" for windows phone 7. Ive created observable collections in my ViewModel that i could bind to, but then i have no way of telling the listbox itemtemplate which collection to bind to when its created.
Any ideas?
I Can post more code if needed.
Thanks!!
Example Observablen Collections in ViewModel
private ObservableCollection<TDItem> _twoDaysAgoItems;
public ObservableCollection<TDItem> TwoDaysAgoItems
{
get { return _twoDaysAgoItems; }
set
{
_twoDaysAgoItems = value;
NotifyPropertyChanged("TwoDaysAgoItems");
}
}
private ObservableCollection<TDItem> _yesterdayItems;
public ObservableCollection<TDItem> YesterdayItems
{
get { return _yesterdayItems; }
set
{
_yesterdayItems = value;
NotifyPropertyChanged("YesterdayItems");
}
}
private ObservableCollection<TDItem> _todayItems;
public ObservableCollection<TDItem> TodayItems
{
get { return _todayItems; }
set
{
_todayItems = value;
NotifyPropertyChanged("TodayItems");
}
}
EntitySet
private EntitySet<TDItem> _tds;
[Association(Storage = "_ts", OtherKey = "_dowId", ThisKey = "Id")]
public EntitySet<TDItem> TDs
{
get { return this._tds;
}
set {
NotifyPropertyChanging("TDs");
this._tds.Assign(value);
NotifyPropertyChanged("TDs");
}
}
public DOW()
{
_tds = new EntitySet<TDItem>(
new Action<TDItem>(this.attach_TD),
new Action<TDItem>(this.detach_TD)
);
}
Pivot
<controls:Pivot x:Name="TDPivotDisplay" SelectedIndex="2" Margin="0,-10,0,0" Grid.Row="0" Title="TD" Foreground="White" FontWeight="light" VerticalAlignment="Top" FontSize="29.333" Style="{StaticResource PivotStyle1}" FontFamily="{StaticResource Akzidenz Grotesk}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="DOW" Foreground="{Binding Colour}" FontSize="110" FontFamily="{StaticResource Akzidenz Grotesk}" Text="{Binding Header}"/>
<TextBlock x:Name = "FullDate" Foreground="{Binding Colour}" FontWeight="light" FontSize="30" FontFamily="{StaticResource Akzidenz Grotesk}" HorizontalAlignment="center" Text="{Binding Date}"/>
</StackPanel>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid Height="421">
<ListBox ItemsSource = "{Binding TDs}" ItemTemplate = "{StaticResource ListboxItemTemp}" x:Name ="TDLists" Margin="12, 0, 12, 0" Width="440"/>
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
Related
I'm becoming crazy i don't understand why my ObservableCollections have a strange behaviour. I have tabs :
<Grid Grid.Row="1">
<TabControl Grid.Row="1">
<TabItem Header="Posts instagrams">
<DataGrid ItemsSource="{Binding InstagramPhotos, Mode=TwoWay}" />
</TabItem>
<TabItem Header="Shop">
<DataGrid ItemsSource="{Binding ShopPhotos, Mode=TwoWay}" />
</TabItem>
<TabItem Header="Articles">
<DataGrid ItemsSource="{Binding ArticlePhotos, Mode=TwoWay}" />
</TabItem>
</TabControl>
</Grid>
The ObservableCollections are defined like this :
private ObservableCollection<PhotoModel> _instagramPhotos;
public ObservableCollection<PhotoModel> InstagramPhotos
{
get => _instagramPhotos ?? (_instagramPhotos = new ObservableCollection<PhotoModel>());
set
{
_instagramPhotos = value;
RaisePropertyChanged("InstagramPhotos");
}
}
private ObservableCollection<PhotoModel> _shopPhotos;
public ObservableCollection<PhotoModel> ShopPhotos
{
get => _shopPhotos ?? (_shopPhotos = new ObservableCollection<PhotoModel>());
set
{
_shopPhotos = value;
RaisePropertyChanged("ShopPhotos");
}
}
private ObservableCollection<ArticleModel> _articlePhotos;
public ObservableCollection<ArticleModel> ArticlePhotos
{
get => _articlePhotos ?? (_articlePhotos = new ObservableCollection<ArticleModel>());
set
{
_articlePhotos = value;
RaisePropertyChanged("ArticlePhotos");
}
}
I bind commands for adding/update/delete element in each collections. The update work fine on every UI. BUT where it's strange is that the Add event works correctly in first tab but delete doesn't. And in other tab, add event doesn't work but delete works. I clearly don't understand why.
FINALLY found out ! I was using this
DataContext="{Binding Source={StaticResource DataViewModel}}"
So it doesn't update. I put it in <Window.DataContext> tag and works well
(Windows Phone 7 SDK)
Hi,
I have a ListBox named CTransactionList, and adding some items to this listbox by using data bindings. And Here I have a class to evaulate data bindings.(I think my listbox's XAML code is not needed here as my issue comes out due to some coding problems)
public class CTransaction
{
public String Date1 { get; set; }
public String Amount1 { get; set; }
public String Type1 { get; set; }
public CTransaction(String date1, String amount1, String type1)
{
this.Date1 = date1;
this.Amount1 = amount1;
switch (type1)
{
case "FR":
this.Type1 = "Images/a.png";
break;
case "TA":
this.Type1 = "Images/b.png";
break;
case "DA":
this.Type1 = "Images/c.png";
break;
}
}
}
Here I have a function, when a move completes, this function runs;(this function is supposed to add new items when function runs)
List<CTransaction> ctransactionList = new List<CTransaction>();//Define my list
public void movecompleted()
{
String DefaultDate = "";
String DefaultAmount = "";
String RandomType = "";
DefaultDate = nameend.Text;
DefaultAmount = diffend.Text;
RandomType = "FR";
ctransactionList.Add(new CTransaction(DefaultDate, DefaultAmount, RandomType));
CTransactionList.ItemsSource = ctransactionList;
}
For the first time when move completes, it adds the required elements to my list. But for next times, it does not add to my list. The old one keeps its existence. I tried also this format by getting list definition into my function like:
public void movecompleted()
{
List<CTransaction> ctransactionList = new List<CTransaction>(); //List definition in function
String DefaultDate = "";
//...Same
}
And this time, it replaces my current item with new one. Do not append at the end of list. (Both ways, I have one item in my list, not more) How can I do everytime append to list? Where am I wrong?
Here is my Debugging report. Both ctransactionList object and CTransactionList ListBox have the needed items according to my observations in debug watcher. Only problem, CTransactionList cant refresh itself properly even if it has the resources retrieved from ctransactionList object.
Here is my XAML code for my relevant listbox.(IF NEEDED)
<Grid>
<ListBox Name="CTransactionList" Margin="0,0,0,0" >
<ListBox.ItemTemplate >
<DataTemplate>
<Button Width="400" Height="120" >
<Button.Content >
<StackPanel Orientation="Horizontal" Height="80" Width="400">
<Image Source="{Binding Type1}" Width="80" Height="80"/>
<StackPanel Orientation="Vertical" Height="80">
<StackPanel Orientation="Horizontal" Height="40">
<TextBlock Width="100" FontSize="22" Text="Name:" Height="40"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Date1}" Height="40"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="40">
<TextBlock Width="100" FontSize="22" Text="Difficulty:" Height="40"/>
<TextBlock Width="200" FontSize="22" Text="{Binding Amount1}" Height="40"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Thanks in advance.
As you rightly mentioned, it's not related to your XAML. Problem is in your code.
First simple fix may to clear the ItemsSource before setting the new source, like this
CTransactionList.ItemsSource = null;
CTransactionList.ItemsSource = ctransactionList;
This way, you are clearing the existing the databinding and enforcing the new list into the ListBox.
The other and suggestible fix is,
"Change your List to ObservableCollection. Because, ObservableCollection extends the INotifyPropertyChanged and hence has the ability to auto update the ListBox"
List<CTransaction> ctransactionList = new List<CTransaction>();//Change this to below
ObservableCollection<CTransaction> ctransactionList = new ObservableCollection<CTransaction>();//Define my collection
But a breakpoint before
CTransactionList.ItemsSource = ctransactionList;
And run the function twice. Do you have two items in ctransactionList now?
I suspect the binding fails and ctransactionList are in fact increasing
I am having a simple list of todo's that's stored in a List-object, that's shown through a ListBox through data binding. The items are clickable, and they take you to a details page, where you can also delete the task. Everything works out fine, but when I click the back-button, I get an ArgumentOutOfRangeException and the app crashes.
Now, I gather this is because the app thinks the list still has items, but I'm not quite sure how to fix it.
The exception is raised on System.Windows.dll - nothing specific. Also, I know the exception is raised after the OnNavigatedTo-event.
XAML (just the listbox - somewhat simplified):
<ListBox Name="MyActivitiesList" ItemsSource="{Binding MyActivities}" SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<StackPanel Margin="0,0,0,12">
<-- context menu was here, but has been removed -->
<TextBlock Text="{Binding Title}" Style="{StaticResource BigHeader}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category.Name}" Style="{StaticResource SubtleText}"/>
<TextBlock Text=" - " Style="{StaticResource SubtleText}"/>
<TextBlock Text="{Binding VotesPercentage}" Style="{StaticResource SubtleText}"/>
<TextBlock Text="% positive" Style="{StaticResource SubtleText}" />
</StackPanel>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-behind:
private MyActivitiesViewModel myActivitiesViewModel;
public MyActivitiesView()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
myActivitiesViewModel = new MyActivitiesViewModel();
this.DataContext = myActivitiesViewModel;
base.OnNavigatedTo(e);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
MyActivitiesList.SelectedItem = null;
base.OnNavigatingFrom(e);
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (((ListBox)sender).SelectedItem != null)
{
var idea = ((ListBox)sender).SelectedItem as Idea;
((ListBox)sender).SelectedItem = null;
Dispatcher.BeginInvoke(() => NavigationUtility.Navigate(new Uri("/View/IdeaView.xaml", UriKind.Relative), idea));
}
}
Any ideas? Help would be greatly appreciated!
I think the problem might be that you are deleting an item from the list while that same item is bound to the current item in the list box.
One easy way to workaround this is to use an ObservableCollection instead of a List - the collection will tell the list box about any deletion using the INotifyCollectionChanged mechanism.
<TextBlock Name="currency" TextWrapping="Wrap" VerticalAlignment="Center"/>
<TextBlock Margin="5,0" Text="{Binding Text, ElementName=currency" TextWrapping="Wrap" VerticalAlignment="Center" FontSize="22" />
I am using the above code for binding property of one field to another in my WP7 application.
i want to do the similar task from back-end. any suggestions??
Bindings are working in a specified data context. You can set the data context of your layout root to the page instance, then you can bind to any of your properties. (DataContext is inherited through the child FrameworkElements.) If you want your binding to update its value whenever you change your property from code, you need to implement INotifyPropertyChanged interface or use Dependency properties.
<Grid x:Name="LayoutRoot">
<TextBox Text="{Binding Test, Mode=TwoWay}" />
</Grid>
public class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
private string test;
public string Test
{
get { return this.test; }
set
{
this.test = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Test"));
}
}
public MainPage()
{
InitializeComponents();
LayoutRoot.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
}
This is a stupid example since you can access your TextBox any time from MainPage, this has much more sense if you are displaying model objects with DataTemplates.
(I typed this on phone, hope it compiles..)
i got my solution as: var b = new Binding{ElementName = "currency", Path = new PropertyPath("Text")}; Textblock txt = new TextBlock(); txt.SetBinding(TextBlock.TextProperty, b);
I've been struggling for a while on this. I'm a bit of a newbie, but i lurked a lot and still couldn't find a solution to my problem, so I decided to post my question here.
I'm binding a pivot to a collection of objects I want to display to create a gallery. Here is my pivot control bound to a list called gallery, where each object contains 2 strings (url and description).
<controls:Pivot ItemsSource="{Binding gallery}" Grid.Row="0" x:Name="galleryPivot">
<controls:Pivot.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="{Binding url}" />
<Grid Visibility="{Binding ElementName=galleryPivot, Path=DataContext.ShowDetail}">
<ListBox>
<ListBoxItem>
<StackPanel>
<TextBlock Text="{Binding description}" />
</StackPanel>
</ListBoxItem>
</ListBox>
</Grid>
</Grid>
</StackPanel>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
The datacontext is the viewmodel and initialized in the constructor of the page.
Here is my ViewModel:
public class GalleryViewModel : INotifyPropertyChanged
{
public List<Gallery> gallery
{
get { return Globals.pictures; }
}
private Visibility _showDetail = Visibility.Collapsed;
public Visibility ShowDetail
{
get { return _showDetail; }
set {
_showDetail = value;
RaisePropertyChanged("ShowDetail");
}
}
public GalleryViewModel()
{ }
public event PropertyChangedEventHandler PropertyChanged = delegate { return; };
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The gallery object is a list in my ViewModel, as the ShowDetail property. As ShowDetail is outside the scope, I tried to set ElementName as explained here.
The pivot binds well to the gallery list, but when I change the value of ShowDetail, the grid won't hide. I also tried to set ElementName to LayoutRoot but it still won't work.
My question, how can I bind the visibility when it is outside the scope of the itemtemplate?
Within a DataTemplate the ElementName binding refers only to the names of elements that are within that DataTemplate. The data context within your data template is the Gallery instance, not the GalleryViewModel. You could move the ShowDetail property down to the Gallery class instead.
If you'd rather not do that, then an alternative would be to use a proxy for the data context, which you add as a resource to the page and bind to the page's data context (a GalleryViewModel instance presumably). You can then reference that resource as you would any other resource to get at the parent data context.
If you're not familiar with this proxy concept, then Dan Wahlin's post on the subject should help.