I have two table. Table 1 from a online service which forms the Listbox on my original Page. The second table is located in an internal DB and contains a uniqie field with the same values as a field in table1.
I want to use a listbox in table 1 to load details from table2 in a seperate page.
The code below is my code from my second page however it keeps throwing an exception "Items Collection must be empty before using ItemSource"
Can someone correct this code or sugest better way to do this?
public partial class PlayerProfilePanoramaPage : PhoneApplicationPage
{
object _SelectedPlayer;
string _playerName;
public CollectionViewSource viewsource { get; set; }
public PlayerProfilePanoramaPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(PhoneApplicationPage_Loaded);
LoadPlayerProfile();
LoadPlayerDetails();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = _SelectedPlayer;
}
private void LoadPlayerProfile()
{
FrameworkElement root2 = Application.Current.RootVisual as FrameworkElement;
var currentplayer = root2.DataContext as Mens_Leaders;
_SelectedPlayer = currentplayer;
_playerName = currentplayer.Name;
}
private void LoadPlayerDetails()
{
ObservableCollection<PlayerProfileTable> playerProfile = new ObservableCollection<PlayerProfileTable>();
viewsource = new CollectionViewSource();
viewsource.Filter += PlayerProfile_Filter;
viewsource.Source = playerProfile;
this.PlayerPanorama.ItemsSource = viewsource.View;
}
void PlayerProfile_Filter(object sender, FilterEventArgs e)
{
if (e.Item != null)
e.Accepted = ((PlayerProfile)e.Item).Name.Equals(_playerName);
}
}
edit: Xaml is currently only simple to text that binding was working. Datacontexts and source bindings not defined in Xaml as defined in code. Xaml code provided below.
<controls:Panorama Name="PlayerPanorama" Title="my application">
<!--Panorama item one-->
<controls:PanoramaItem Name="panoramaPage1" Header="item1">
<Grid Name="Grid1">
<StackPanel>
<TextBlock Height="30" Name="textBlock1" Text="{Binding PlayerName, FallbackValue=Name}" />
<TextBlock Height="30" Name="textBlock2" Text="{Binding Height, FallbackValue=Height}" />
<ScrollViewer Height="387" Name="scrollViewer1" Width="422">
<TextBlock Height="auto" Name="textBlock3" Text="{Binding ProfileBlurb, FallbackValue=Blurb}" />
</ScrollViewer>
</StackPanel>
</Grid>
</controls:PanoramaItem>
Related
I have a lot of bindings in a grid which are collapsed or visible based on the selecteditem in a treeview tree. so based on the object, the correct view pops up and the other collapses.
But I get lots of binding errors of the gui elements in the collapsed views. that is so, because I have a "myselecteditem" in the view model that fits to the view which is opened, but not to the collapsed ones.
is my approach stupid? can i suppress bindings for gui elemnts in a collapsed grid?
Code (shorted for lazy readers):
XAML:
<Grid x:Name="G_G_Content" Grid.Column="1">
<Grid x:Name="G_G_Abrechnung_Control" Visibility="Collapsed">
[...]
</Grid>
<Grid x:Name="G_G_Mitglied_Aktion" Visibility="Collapsed">
[...]
</Grid>
<Grid x:Name="G_G_Mitglied_Aktion_Nachweis" Visibility="Visible">
[...]
</Grid>
</Grid>
<TreeView
x:Name="G_tv_explorer"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding TreeViewItemSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItemChanged="G_tv_explorer_SelectedItemChanged"
TreeViewItem.Expanded="TreeViewItem_Expanded" />
C#:
private void G_tv_explorer_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
//set active treeviewitem
if (G_tv_explorer.SelectedItem != null)
{
//set treeview && ViMo
ViMo.TreeViewSelectedItem = e.NewValue;
RedrawGui();
ViMo.MySelectedItem = ((TreeViewItem)e.NewValue).Tag;
}
}
public void RedrawGui()
{
//redraw gui, dependant on selectedtreeviewitem
if (ViMo.TreeViewSelectedItem != null)
{
if(ViMo.TreeViewSelectedItem is string)
MessageBox.Show("Dummy");
else
{
//this is a placeholder
if (((TreeViewItem)ViMo.TreeViewSelectedItem).Header.ToString() == "Verwaltung")
{
G_G_Mitglied_Aktion_Nachweis.Visibility = System.Windows.Visibility.Collapsed;
G_G_Abrechnung_Control.Visibility = System.Windows.Visibility.Visible;
}
else if (((TreeViewItem)ViMo.TreeViewSelectedItem).Tag is MVVM.Model.Jahresabschluss)
{
G_G_Mitglied_Aktion_Nachweis.Visibility = System.Windows.Visibility.Collapsed;
G_G_Abrechnung.Visibility = System.Windows.Visibility.Visible;
}
}
}
}
Where RedrawGUI only sets the Grids Visible / collapsed based on the Object Type of the SelectedItem
I am pretty new to WPF and I have tried figuring out how to add a Label appear inside a the following ListView which shows the number of Items currently in the ListView. I've given the ListView padding on the top to make room for the Label.
<ListView x:Name="MyListView" Grid.Row="0" Grid.Column="0" Margin="0,40,0,0" Padding="0" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding DatasetCode}" FontWeight="Bold"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If anyone can help me out, it would be greatly appreciated.
Edit the Template of ListBox. You can do this by Right-Clicking the ListBox in the Document outline section. And add your Label as below.
...
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<StackPanel>
<Label uc:Window2.CountFor="False" />
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</StackPanel>
</ScrollViewer>
...
I have written an attached property CountFor . Code is give below :
#region CountFor attached property
public static bool GetCountFor(DependencyObject obj)
{
return (bool)obj.GetValue(CountForProperty);
}
public static void SetCountFor(DependencyObject obj, bool value)
{
obj.SetValue(CountForProperty, value);
}
// Using a DependencyProperty as the backing store for CountFor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CountForProperty =
DependencyProperty.RegisterAttached("CountFor", typeof(bool), typeof(Window2), new PropertyMetadata(false, new PropertyChangedCallback(GetCountForChanged)));
private static void GetCountForChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == false) return;
Label lbl = (Label)d;
lbl.Loaded += (o, args) =>
{
DependencyObject parent = VisualTreeHelper.GetParent(lbl);
while (parent.GetType() != typeof(ListBox))
parent = VisualTreeHelper.GetParent(parent);
ListBox lb = (ListBox)parent;
ICollectionView view = CollectionViewSource.GetDefaultView(lb.ItemsSource);
lbl.Content = "Number of items = " + ((ListCollectionView)view).Count;
view.CollectionChanged += (col, colargs) =>
{
lbl.Content = "Number of items = " + ((ListCollectionView)col).Count;
System.Diagnostics.Debug.WriteLine(((ListCollectionView)col).Count.ToString());
};
};
}
#endregion
Your solution is simple, you could just create an int to count the number of items in your label and then assign a new textblock, you could also completely skip the textblock and simply add the int, check this code:
private void button1_Click(object sender, RoutedEventArgs e)
{
int testcounter;
testcounter = listBox.Items.Count;
TextBlock BlockCounter = new TextBlock();
BlockCounter.Text = testcounter.ToString();
listBox.Items.Add(BlockCounter);
}
Im tweaking a Sound Player app to try and include a Save as Ringtone function. App uses Tiles and a Viewmodel. Tapping each tile plays a sound. I added a Context Menu to the Data Template to give the option on a Tap and Hold event to save that sound as a Ringtone. I am having some issues figuring out just how to use the same source as the Tiles use to play the sound. Below, first code is portion of the Mainpage.xaml. Then the c# code. What I have set at the bottom of the MainPage.cs for the _customRingtone Source is wrong. The emulator stops at "SoundData data = selector.SelectedItem as SoundData;" I cant figure out how to do the source in a similar way the Tile taps get the audio for playing it. I didnt post the ViewModel but can if you want me to. That is where the Tile Groups and sounds are loaded.
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="SoundTileDataTemplate">
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Click="Save_Click" Header="Save as Ringtone" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Grid Background="{StaticResource PhoneAccentBrush}"
Margin="0, 0, 12, 12">
<Grid VerticalAlignment="Top"
HorizontalAlignment="Right"
Width="40"
Height="40"
Margin="0, 6, 6, 0">
<Ellipse Stroke="{StaticResource PhoneForegroundBrush}"
StrokeThickness="3" />
<Image Source="/Assets/AppBar/Play.png" />
</Grid>
<StackPanel VerticalAlignment="Bottom">
<TextBlock Text="{Binding Title}" Margin="6, 0, 0, 6" />
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<MediaElement
Name="AudioPlayer"
Volume="1" />
<!--Pivot Control-->
<phone:Pivot Title="{Binding Path=LocalizedResources.ApplicationTitle,
Source={StaticResource LocalizedStrings}}">
<phone:PivotItem Header="{Binding Animals.Title}">
<phone:LongListSelector x:Name="Animal"
SelectionChanged="LongListSelector_SelectionChanged"
Margin="0,0,-12,0"
ItemsSource="{Binding Animals.Items}"
LayoutMode="Grid"
GridCellSize="150,150"
ItemTemplate="{StaticResource SoundTileDataTemplate}"
/>
</phone:PivotItem>
public partial class MainPage : PhoneApplicationPage
{
private readonly SaveRingtoneTask
_CustomRingtone;
// Constructor
public MainPage()
{
InitializeComponent();
// Set the data context of the listbox control to the sample data
DataContext = App.ViewModel;
_CustomRingtone = new SaveRingtoneTask();
_CustomRingtone.Completed +=
customeRingtone_Completed;
BuildLocalizedApplicationBar();
}
// Load data for the ViewModel Items
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
}
private void LongListSelector_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
LongListSelector selector = sender as LongListSelector;
// verifying our sender is actually a LongListSelector
if (selector == null)
return;
SoundData data = selector.SelectedItem as SoundData;
// verifying our sender is actually SoundData
if (data == null)
return;
private void customeRingtone_Completed(object sender, TaskEventArgs e)
{
if (e.TaskResult == TaskResult.OK)
{
MessageBox.Show(#"Saved");
}
else if (e.TaskResult == TaskResult.Cancel)
{
MessageBox.Show(#"Canceled");
}
else
{
MessageBox.Show(#"Not Saved");
}
}
private void Save_Click(object sender, System.Windows.RoutedEventArgs e)
{
LongListSelector selector = sender as LongListSelector;
SoundData data = selector.SelectedItem as SoundData;
**_CustomRingtone.Source = new Uri(data.FilePath, UriKind.RelativeOrAbsolute**);
_CustomRingtone.DisplayName = "Ring";
_CustomRingtone.Show();
}
You Save_Click event handler is not passed a LLS, but a context MenuItem. The DataContext of the MenuItem is the object you are after.
private void Save_Click(object sender, System.Windows.RoutedEventArgs e)
{
var element = (FrameworkElement)sender;
SoundData data = element.DataContext as SoundData;
_CustomRingtone.Source = new Uri(data.FilePath, UriKind.RelativeOrAbsolute**);
_CustomRingtone.DisplayName = "Ring";
_CustomRingtone.Show();
}
Here is my code. What it doing. I have one textbox(button) with text Book name, when I click on it I can change text in textbox using binding. But now I add another textbox for author name and I dont know how bind it. If I use same method like for Book name its not works or text from book name is too in book author. All text are changed via popup setting page.
My source here: https://dl.dropbox.com/u/40039421/App1.rar.
Image here: https://dl.dropbox.com/u/40039421/helpp.png
public partial class MainPage : INotifyPropertyChanged
{
private ObservableCollection<Book> _books = new ObservableCollection<Book>();
public ObservableCollection<Book> AllBooks
{
get { return _books; }
set { _books = value; }
}
...
private void InitializeData()
{
var bookName1 = new Book { Id = 1, BookName = "Small red apple",AuthorName = "Daniel"};
...
AllBooks.Add(bookName1);
...
OnPropertyChanged("AllBooks");
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}
}
private void btnGreenBook_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null)
{
Popup popup = new Popup();
popup.VerticalOffset = 30;
PopupSettingPage control = new PopupSettingPage();
popup.Child = control;
popup.IsOpen = true;
control.btnSave.Click += (s, args) =>
{
var id = Convert.ToInt32(button.Tag);
var book = AllBooks.FirstOrDefault(sub => sub.Id == id);
if (book != null)
{
book.BookName = control.BookName;
book.OnPropertyChanged("BookName");
}
popup.IsOpen = false;
};
...
Ohh dear, it was a simple mistake :)
You forgot to add the AuthorName in the Xaml of your PopupSettingsPage.xaml
<TextBox x:Name="tbInputAuthorName" Text="{Binding AuthorName, Mode=TwoWay}" VerticalAlignment="Center"/>
And then in MainPage do this
book.BookName = control.BookName;
book.OnPropertyChanged("BookName");
book.AuthorName = control.AuthorName;
book.OnPropertyChanged("AuthorName");
Additional answer based on your comments:
In order to achieve that, You have to remove the second stackpanel in the listbox. Instead, use the WrapPanel control. Search for how to use WrapPanel for WindowsPhone.
And then you have to find some way to set the backgrounds as red or green. Good luck
OK I use wrap panel but problem is still here. I have two panorama items (I post code from item 1 and item 2 have same code only is showing on second panorama page) and problem is still if I save some value to one of item in panorama item 1 this value is too in panorama item 2 and I dont know how make it. Logic is click on panorama 1 item change values in panoam 1 items, click on panorama 2 items change panorama 2 items values. Its look like panoram item 1 have same ID like panoram item 2. Here is full source : https://dl.dropbox.com/u/40039421/App1SecondEdit.rar
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Panorama control-->
<phone:Panorama>
<!--Panorama item 1-->
<phone:PanoramaItem Header="Test">
<Grid x:Name="PanelPanoramaItem1"
Grid.Row="1"
Margin="25,0,12,0">
<ListBox ItemsSource="{Binding AllBooks}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Width="140"
Height="140"
toolkit:TiltEffect.IsTiltEnabled="True" Margin="0,0,0,5" Click="Button_Click_1" Tag="{Binding Id}" >
<Button.Template>
<ControlTemplate>
<Grid Background="Chartreuse">
<TextBlock Foreground="Black" Text="{Binding BookName}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</phone:PanoramaItem>
<!-- END Panorama item 1 -->
I'm using a ListBox to display all values contained in Dictionary<> object:
<ListBox Height="519" x:Name="ContactsListBox" Width="460" Margin="0,0,0,0" SelectionChanged="ContactsListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Key}" Margin="5" Foreground="{StaticResource PhoneAccentBrush}"/>
<TextBlock x:Name ="LastNameData" Text="{Binding Value}" Margin="20, 0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Content is filled by the following code:
Dictionary<long, Contact> contacts = new Dictionary<long, Contact>();
this.ContactsListBox.ItemsSource = contacts;
Now, I would like to 'know' which specific "Contact" in ListBox is currently selected, either by knowing its Key, or just by extracting value from "LastNameData" TextBlock.
I tried doing something like that, but obviosly it doesn't work:
private void ContactsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lb = this.ContactsListBox.SelectedItem as ListBox;
this.Test_SomeOtherTextBlock.Text = lb.ToString();
}
I would really appreciate your help!
you can even do the follwing:
<ListBox Height="519" x:Name="ContactsListBox" Width="460" Margin="0,0,0,0" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Key}" Margin="5"/>
<TextBlock x:Name ="LastNameData" Text="{Binding Value}" Margin="20, 0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid DataContext="{Binding ElementName=ContactsListBox, Path=SelectedItem}" Margin="0,470,0,0">
<TextBlock Text="{Binding Value}"/>
</Grid>
So you don't need code behind...
BR,
TJ
There are several problems:
In Xaml you probably don't want to display the class name, but a reasonable string, for example:
<TextBlock x:Name ="LastNameData" Text="{Binding Value.LastName}" Margin="20, 0" />
In the selection processing the selected item is KeyValuePair<...>. You could easily find it yourself, if you looked at the returned type in debugger. (Should be kind of a reflex for a programmer, hence a questions like above should never appear :))
private void ContactsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
KeyValuePair<long, Contact> kv = (KeyValuePair<long, Contact>)this.ContactsListBox.SelectedItem;
Contact c = (Contact)kv.Value;
Debug.WriteLine(c.LastName);
}
Your code is good, using ListBox.SelectedItem is the right approach.
I think the problem is that you should cast it as ListBoxItem, not ListBox. And also to get to its value using DataContext, so something like along these lines (not tested, I'm not sure about accessing DataContext value in the last line):
private void ContactsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem lbi = this.ContactsListBox.SelectedItem as ListBoxItem;
var dataContext = lbi.DataContext;
this.Test_SomeOtherTextBlock.Text = dataContext.Value.ToString();
}
Try this it works for me, will help you to...
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox ContactListBox = sender as ListBox;
ListBoxItem listBoxItem = ContactListBox .ItemContainerGenerator.ContainerFromItem(ContactListBox.SelectedItem) as ListBoxItem;
if (listBoxItem == null)
{
return;
}
TextBlock txtBlock = FindVisualChildByName(listBoxItem, "ListTextBlock");
MessageBox.Show(txtBlock.Text);
}
private static T FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
string controlName = child.GetValue(NameProperty) as string;
if (controlName == name)
{
return child as T;
}
T result = FindVisualChildByName<T>(child, name);
if (result != null)
return result;
}
return null;
}
private void ContactsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lb = this.ContactsListBox.SelectedItem as ListBox;
this.Test_SomeOtherTextBlock.Text = lb.ToString();
}
will go something like this..
private void ContactsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lb = this.ContactsListBox.SelectedItem as ListBox;
DataTemplate template=lb.ContentTemplate;
//Now here you have to extract the content of the data template
and then you need to extract the TextBlock from that content.
}
This is just an overview of the functionality.Sorry not able to post complete code.