Modifiing ItemsSource within BackgroundWorker Causes an Exception - c#

I have a ListBox with an ObservableCollection as ItemsSource in my application.
Also I have serveral classes that provides data for this ItemsSource.
public ObservableCollection<Notification> NotificationItems { get; set; }
private object _stocksLock = new object();
I create the collection within my constructor like that
this.NotificationItems = new ObservableCollection<Notification>();
System.Windows.Data.BindingOperations.EnableCollectionSynchronization(
this.NotificationItems, _stocksLock);
I am loading the modules providing data for the ListBox from serveral dll assemblies. The method to get Notification data for the collection is called within a BackgroundWorker
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += GetPluginModuleNotifications;
List<IModul> Modules = new List<IModul>();
//[...]
foreach (IModul PluginModul in AssemblyList)
{
//[...]
Modules.Add(PluginModul);
//[...]
}
this.Notifications.ItemsSource = this.NotificationItems;
object[] Parameter = new object[] { Modules, this.ComponentFactory,
this.MyListBox};
//-->Edited
worker.WorkerReportsProgress = true;
worker.ProgressChanged += OnProgressChanged;
//<--Edited
worker.RunWorkerAsync(Parameter);
//...
//-->EDITED
private void OnProgressChanged(object sender, ProgressChangedEventArgs e)
{
Notification toAdd = (Notification)e.UserState;
this.NotificationItems.Add(toAdd);
}
//<--EDITED
I want each of the IModul items to provide Items for the ListBox.
This part works fine at all so the data I want to receive is loaded.
Here is my BackgroundWorker.DoWork Event
private void GetPluginModuleNotifications(object sender, DoWorkEventArgs e)
{
object[] args = e.Argument as object[];
if (args == null || args.Length != 3) return;
List<IModul> Module = args[0] as List<IModul>;
IComponentFactory Factory = args[1] as IComponentFactory;
// DXListBox lb = args[2] as DXListBox;
if (Module == null || Factory == null) return;
foreach (IModul Modul in Module)
{
Notification[] res = Modul.GetImportantNotifications(Factory);
if (res == null || res.Length == 0) continue;
foreach (Notification notif in res)
{
//-->EDITED
(sender as BackgroundWorker).ReportProgress(1, notif);
System.Threading.Thread.Sleep(100);
//this.ReceiveNotification(notif);
//<--EDITED
}
}
}
private void ReceiveNotification(Notification obj)
{
if (obj == null) return;
Dispatcher.BeginInvoke(new Action(() =>
{
this.NotificationItems.Add(obj);
if (this.NotificationPanel.Width.Value == 0)
this.NotificationPanel.Width = new GridLength(NOTIFICATION_BAR_WIDTH);
}));
}
The XAML for the NotificationPanel looks like this:
.<dx:DXListBox x:Name="Notifications" VerticalAlignment="Stretch" BorderBrush="Transparent" MouseDoubleClick="NotificationGotoSource" ItemsSource="{Binding NotificationItems}">
<dx:DXListBox.ItemTemplate>
<DataTemplate DataType="{x:Type cbcore:Notification}">
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="38" />
<ColumnDefinition Width="*" MinWidth="157"/>
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ImageSource}" Grid.Column="0" Width="32" Height="32" VerticalAlignment="Top" HorizontalAlignment="Left" />
<StackPanel Orientation="Vertical" Grid.Column="1">
<Label FontWeight="Bold" FontSize="10" MaxHeight="25" MaxWidth="150">
<TextBlock Text="{Binding Headline}" TextWrapping="Wrap" />
</Label>
<Label FontWeight="Normal" FontSize="9" MaxHeight="100" MaxWidth="150">
<TextBlock Text="{Binding Note}" TextWrapping="Wrap" />
</Label>
</StackPanel>
<Label Cursor="Hand" Padding="0" Margin="0" MouseLeftButtonUp="Notification_RemoveSelected" Grid.Column="2"
OverridesDefaultStyle="True" BorderBrush="Black" Background="Transparent"
FontSize="8" FontWeight="Bold" VerticalAlignment="Top" HorizontalAlignment="Right">
<TextBlock Foreground="Red" TextAlignment="Center">X</TextBlock>
</Label>
</Grid>
</StackPanel>
</DataTemplate>
</dx:DXListBox.ItemTemplate>
</dx:DXListBox>
When I am running my application it will cause an XamlParseException that the object is owned by another thread and the main ui thread cannot acces it.
Can anyone help me to solve that problem?

Set the BackgroundWorker.WorkerSupportProgress to True and attach the ProgressChangedEvent. Replace your ReceiveNotification method with ReportProgress calls to update the UI. The ProgressChangedEventHandler is marshalling to the UI thread, so no invokerequired.

I think you use the wrong dispatcher. In your case you use the dispatcher of the background worker.
Try to keep a refererence of the UI Dispatcher, according to here You just need to access with Application.Current.Dispatcher.

The exception was thrown not cause the ObservableCollection was owned by another Thread, but the public BitmapImage ImageSource within the Notification model.
When the application tries to read the BitmapImage using Binding it fails. So my solution looks like following:
private BitmapImage _ImageSource = null;
public object _originalImageSource= null;
public object ImageSource
{
get { return this._ImageSource; }
set
{
this._originalImageSource = value;
if (this._ImageSource != value)
{
this._ImageSource = value is BitmapImage ? (BitmapImage)value :
value is Uri ?
new BitmapImage(value as Uri) :
new BitmapImage(new Uri(value.ToString()));
this.RaisePropertyChanged("ImageSource");
}
}
}
Within the OnProgressChanged Method I create a 1:1 copy of the Notification using the _originalImageSource to create a new BitmapImage
//-->EDITED
private void OnProgressChanged(object sender, ProgressChangedEventArgs e)
{
Notification t = (Notification)e.UserState;
Notification toAdd = new Notification(t.Parent, t.OriginalSource, t.Headline, t.Note, t._originalImageSource);
this.NotificationItems.Add(toAdd);
if (this.NotificationItems.Count > 0 && this.NotificationPanel.Width.Value == 0)
this.NotificationPanel.Width = new GridLength(NOTIFICATION_BAR_WIDTH);
}
//<--EDITED
Thanks a lot for your support.

Related

Binding data in stackpanel

I use WPF and c#.
I have an issue regarding binding and visibility.
I have a tree which is bound to obsCol1. Then I have a form in a grid whose datacontext is set to `
DataContext="{Binding ElementName=tree, Path=SelectedItem}">`
Inside that form I have 3 identical subforms if you will. Each of the 3 subforms is a groupbox inside of which is a horizontal stack panel in which there is a label textbox label textbox button.
<GroupBox Grid.Column="3" Grid.Row="8" Grid.ColumnSpan="3">
<GroupBox.Header>Reklama 1</GroupBox.Header>
<StackPanel Name="Rek1" DataContext="Reklame" Orientation="Horizontal">
<Label Grid.Column="3" Grid.Row="10" HorizontalAlignment="Right" VerticalAlignment="Top">Datum post/zam</Label>
<xctk:DateTimePicker x:Name="dtReklama1"
Grid.Row="10"
Grid.Column="4"
Height="25"
Margin="3"
Padding="3"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="150" Value="{Binding Path=Opr_brendiranje}"/>
<Label Grid.Column="3" Grid.Row="8" HorizontalAlignment="Right" VerticalAlignment="Top">Dimenzija</Label>
<extToolkit:WatermarkTextBox x:Name="Reklama" Grid.Row="8"
Grid.Column="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="100"
Height="25"
Padding="3"
Margin="3"
AcceptsReturn="True"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Validation.Error="Validation_Error">
<extToolkit:WatermarkTextBox.Watermark>
<TextBox Text="Reklama" Margin="4,2,2,0" FontWeight="Regular" Foreground="Silver" BorderThickness="0"/>
</extToolkit:WatermarkTextBox.Watermark>
<extToolkit:WatermarkTextBox.Text>
<Binding Path="RekDimenzije" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"/>
</extToolkit:WatermarkTextBox.Text>
</extToolkit:WatermarkTextBox>
<Button Grid.Column="5" Grid.Row="9" Height="20" Width="15" Click="Dodaj_Reklamu" VerticalAlignment="Top" FontWeight="Bold" Margin="5" >+</Button>
</StackPanel>
</GroupBox>
So now I need to bind this but the issue is that these subforms use a different class from the form itself. They are an entity in and of itself. So I was wondering if there was any way to bind them independently somehow like itemsource the groupbox or the stack panel or soemthing. I tried using itemscontrol and binding to it but that did not work it would bind the itemsource but if the itemsource was empty the control would dissapear therefore not allowing the user to add it.
Any help would be appreciated.
Update:
Ok so I have a single usercontrol.
On the left side is a tree that uses a HierarchicalDataTemplate that is bound to 2 different classes one of which OrgSredstva is OrgClass with Sredstva class contained within.
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Org_Sredstva}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Path=Organizacije_Naziv}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Ossr_Naziv}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
This all works as complicated as it sounds the tree works fine.
On the right side is a grid that like i described above has datacontext set to whatever is selected in the tree. I need this so that when the selection changes in the tree the form changes with it. The issue is that neither of the classes the tree is bound to is the class the form should be bound to. So the grid can't find the data because the textbox bindings aren't in that observable collection but another one. The way I solved this is to bind every textbox.text property in codebehind so
public void OdabranoDrvo()
{
OdabranaOrg = this.View.tree.SelectedItem as Organizacije;
if (OdabranaOrg != null)
{
string orgId = OdabranaOrg.Organizacije_Sifra;
IEnumerable<Opremljenost> odabranaOpr = from fn in _oprema
where fn.Opr_org_sifra == orgId
select fn;
var ob = new ObservableCollection<Opremljenost>(odabranaOpr);
if (ob.Count > 0)
{
foreach (Opremljenost opr in odabranaOpr)
{
this.View.Povrsina.Text = opr.Opr_Povrsina.ToString();
this.View.RadnoVrijeme.Text = opr.Opr_RadnoVrijeme;
if (opr.Opr_Vlasnik == 1)
{
this.View.LutRad.IsChecked = true;
this.View.ImeVlasnika.IsReadOnly = true;
}
else
{
this.View.LutRad.IsChecked = false;
this.View.ImeVlasnika.IsReadOnly = false;
}
this.View.ImeVlasnika.Text = opr.Opr_ime_vlasnik;
if (opr.Opr_brojilo == 1)
{
this.View.Brojilo.IsChecked = true;
}
else
{
this.View.Brojilo.IsChecked = false;
}
if (opr.Opr_ventilacija == 1)
{
this.View.Ventilacija.IsChecked = true;
}
else
{
this.View.Ventilacija.IsChecked = false;
}
this.View.dtBrendiranje.Value = opr.Opr_brendiranje;
this.View.dtKrecenje.Value = opr.Opr_krecenje;
this.View.Napomena.Text = opr.Opr_napomena;
this.View.BrojAparata.Text = opr.Opr_broj_aparata.ToString();
this.View.BrojRuleta.Text = opr.Opr_broj_ruleta.ToString();
this.View.UkupanBrojKlima.Text = opr.Opr_uku_br_klima.ToString();
this.View.BrojKlimaLutrija.Text = opr.Opr_br_kl_lut.ToString();
this.View.UkupanBrojTv.Text = opr.Opr_uku_broj_tv.ToString();
this.View.BrojTvLutrija.Text = opr.Opr_broj_tv_lut.ToString();
this.View.BrojTvPartneri.Text = opr.Opr_broj_tv_partneri.ToString();
this.View.StrujnaSnaga.Text = opr.Opr_struja_ang_snaga.ToString();
_slikeOpr = Ap.GlavniRepository.UcitajSlikeZaOpremu(opr.Opr_Id);
this.View.Thumbnails.ItemsSource = _slikeOpr;
_reklame = Ap.GlavniRepository.UcitajReklameZaOpremu(opr.Opr_Id);
int i = _reklame.Count();
if (i == 2)
{
this.View.Rek2.Visibility = Visibility.Visible;
this.View.Rek3.Visibility = Visibility.Collapsed;
}
else if (i == 3)
{
this.View.Rek2.Visibility = Visibility.Visible;
this.View.Rek3.Visibility = Visibility.Visible;
}
else
{
this.View.Rek2.Visibility = Visibility.Collapsed;
this.View.Rek3.Visibility = Visibility.Collapsed;
}
this.View.Reklame.DataContext = _reklame;
}
}
else
{
this.View.Povrsina.Text = "0";
this.View.RadnoVrijeme.Text = String.Empty;
this.View.LutRad.IsChecked=false;
this.View.ImeVlasnika.Text = String.Empty;
this.View.Brojilo.IsChecked = false;
this.View.Ventilacija.IsChecked = false;
this.View.dtBrendiranje.Value = DateTime.Now;
this.View.dtKrecenje.Value = DateTime.Now;
this.View.Napomena.Text = String.Empty;
this.View.BrojAparata.Text = "0";
this.View.BrojRuleta.Text = "0";
this.View.UkupanBrojKlima.Text = "0";
this.View.BrojKlimaLutrija.Text = "0";
this.View.UkupanBrojTv.Text = "0";
this.View.BrojTvLutrija.Text = "0";
this.View.BrojTvPartneri.Text = "0";
this.View.StrujnaSnaga.Text = "0";
this.View.Thumbnails.ItemsSource = null;
this.View.Rek2.Visibility = Visibility.Collapsed;
this.View.Rek3.Visibility=Visibility.Collapsed;
}
}
}
The original question i resolved by creating a new grid inside my preexisting grid and just setting the data context for that inner grid to what I needed it to be. Now I find that all the bindings seem to work at least on reading from database, haven't tested inserting into database yet.
I realise this is all very ugly but I couldn't figure out a way to actually bind it while it still working as it should...

Reach a TextBlock from a specific ListViewItem from the ListView in Windows Phone 8.1 XAML programmatically

I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.

Telerik RadJumpList using DataVirtualizationMode.Automatic

I have a problem where im trying to use a Telerik Jump List with DataVirtualizationMode.Automatic, but i can't get it to work. The reason why i want to use this, is because i want my app to only download the data(games) which is in the current view of the Jump List control and not the whole data everytime. For example if i have searched for "Batman", and its returning 50 games, i don't want it to download and load all the games, only those i can see in the Jump List control.
Here is a sample of using DataVirtualizationMode.Automatic from Telerik, but i couldn't get it to work with my app: http://www.telerik.com/help/windows-phone/raddataboundlistbox-features-datavirtualization-automatic.html
Below is my Jump List control which i want to use with data virtualization.
MainPage.xaml:
<phone:PivotItem Header="Browse">
<Grid>
<telerikPrimitives:RadTextBox Name="txtSearch" HorizontalAlignment="Left" VerticalAlignment="Top" Height="80" Width="390"/>
<telerikPrimitives:RadImageButton Name="imgBtnSeachGame" VerticalAlignment="Top" HorizontalAlignment="Right" ButtonShape="Ellipse" BorderThickness="2" Margin="0,8,0,0" Click="imgBtnSeachGame_Click"></telerikPrimitives:RadImageButton>
<Controls:RadJumpList Name="jlGameList" ItemsSource="{Binding}" Tap="jlGameList_Tap" Margin="0,90,0,0" DataVirtualizationMode="Automatic">
<Controls:RadJumpList.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="{StaticResource PhoneAccentBrush}"
Padding="{StaticResource PhoneTouchTargetOverhang}"
Margin="0,0,0,0">
<TextBlock Name="tblGameTitle" Style="{StaticResource PhoneTextGroupHeaderStyle}" ManipulationStarted="tblGameTitle_ManipulationStarted" ManipulationCompleted="tblGameTitle_ManipulationCompleted">
<Run Text="{Binding GameTitle}"></Run>
</TextBlock>
</Border>
<Grid Background="#242424" Grid.Row="1">
<Image Name="imgGameList" Margin="0,0,0,0" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top" Height="96" Width="96">
<Image.Source>
<BitmapImage UriSource="{Binding BoxArtFrontThumb}"
CreateOptions="BackgroundCreation" DecodePixelHeight="96" DecodePixelWidth="96" />
</Image.Source>
</Image>
<TextBlock Margin="110,0,0,0" Text="Platform" FontWeight="Bold" TextWrapping="Wrap" Foreground="YellowGreen" FontSize="{StaticResource PhoneFontSizeNormal}"/>
<TextBlock Name="txtPlatform" Margin="110,20,0,0" Text="{Binding Platform}"></TextBlock>
<TextBlock Text="Release Date" FontWeight="Bold" Margin="110,46,0,0" Foreground="YellowGreen" FontSize="{StaticResource PhoneFontSizeNormal}"/>
<TextBlock Name="txtReleaseDate" Margin="110,66,0,0" Text="{Binding ReleaseDate}"></TextBlock>
<!--</StackPanel>-->
</Grid>
<Grid Grid.Row="2"></Grid>
</Grid>
</DataTemplate>
</Controls:RadJumpList.ItemTemplate>
</Controls:RadJumpList>
</Grid>
</phone:PivotItem>
Below is where i bind my DataContext to my GetGamesListItems ObservableCollection in my GameData class. The imgBtnSearchGame_Click event method is being called when a user have typed for example "Batman" in my textbox txtSearch and tapped the button, it will then send the text to my GetGamesListData method.
MainPage.cs:
GameData gd = new GameData();
public MainPage()
{
InitializeComponent();
jlGameList.DataContext = gd.GetGamesListItems;
}
private void imgBtnSeachGame_Click(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(txtSearch.Text))
{
gd.GetGamesListData(txtSearch.Text, "", "");
}
}
Below is where i download the data in XML for the game name searched for. For example if it is "Batman" it will find and return all games with "Batman". The "BoxArtFrontThumb" Property is where im storing all the images for each game and is using async, because sometimes there can be quite alot of images it has to download and show.
GameData.cs
public void GetGamesListData(string name, string platform, string genre)
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += GetGamesListRequestCompleted;
webClient.DownloadStringAsync(new Uri("http://thegamesdb.net/api/GetGamesList.php?name=" + name));
}
private async void GetGamesListRequestCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
GetGamesListItems.Clear();
var feedXml = XDocument.Parse(e.Result);
var gameDataTasks = feedXml.Root.Descendants("Game").Select(
async x => new GetGamesList
{
ID = (int)x.Element("id"),
GameTitle = (string)x.Element("GameTitle"),
ReleaseDate = (string)x.Element("ReleaseDate") ?? "N/A",
Platform = (string)x.Element("Platform") ?? "N/A",
BoxArtFrontThumb = new Uri(await GetBoxArtFrontThumbAsync((int)x.Element("id")), UriKind.RelativeOrAbsolute),
}).ToList();
var gameData = await Task.WhenAll(gameDataTasks);
foreach (var item in gameData)
{
GetGamesListItems.Add(item);
}
}
}
Below is where its finding and storing the images for the games.
public async Task<string> GetBoxArtFrontThumbAsync(int id)
{
var client = new HttpClient();
var result = await client.GetStringAsync("http://thegamesdb.net/api/GetArt.php?id=" + id);
var feedXml = XDocument.Parse(result);
var gameData = feedXml.Root.Descendants("Images").Select(x => new GetArt
{
BoxArtFrontThumb = new Uri(GetBoxArtFrontThumb(x), UriKind.RelativeOrAbsolute),
}).ToList();
return gameData.Single().BoxArtFrontThumb.ToString();
}
private static string GetBoxArtFrontThumb(XElement gameNode)
{
string data = "http://thegamesdb.net/banners/" + (string)gameNode.Descendants("boxart")
.FirstOrDefault(b => (string)b.Attribute("side") == "front");
if (data == "http://thegamesdb.net/banners/")
{
data = "/NoImage.jpg";
}
return data;
}
I really hope i explained this well enough and hope that there is someone that can help me solve this problem. Thanks.
Although you are using JumpList, the mechanism for Virtualizing the data is the same as the DataBoundListBox. (You can find more information here in the DataBoundListBox docs. There is a good tutorial using an OData service.)
In order for the Automatic mode to work properly, you need to be using Telerik's VirtualizingDataCollection object and initialize it with the proper arguments (count and page size).
I don't see this in the code you have provided above, can you please open a support ticket so that I can investigate further? See my comment above for the link. Let me know the ticket number and I'll provide further assistance.

Windows Phone "ListBox" ItemsSource

I have a list and want to assign the downloaded feeds her. Also wanted to say that I am using the same code I've used in another app, but is giving an error as few as this. The other works perfectly. I will post few as the source of this. For if you can not stay too long.
private void carregaListas()
{
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new System.Uri("http://www.news-medical.net/syndication.axd?format=rss"));
}
private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
stkLife.Visibility = Visibility.Visible;
stbOfLife.Begin();
});
}
else
{
// Save the feed into the State property in case the application is tombstoned.
//gridProgressBar.Visibility = Visibility.Collapsed;
this.State["feed"] = e.Result;
UpdateFeedList(e.Result);
}
}
private void UpdateFeedList(string feedXML)
{
StringReader stringReader = new StringReader(feedXML);
XmlReader xmlReader = XmlReader.Create(stringReader);
SyndicationFeed feed = SyndicationFeed.Load(xmlReader);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
feedListBox.ItemsSource = feed.Items;
});
}
Error: "Items collection must be empty before using ItemsSource."
XAML code:
<ListBox x:Name="feedListBox" Margin="0,0,-12,0" SelectionChanged="feedListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<StackPanel.Background>
<SolidColorBrush Color="#FFC5C5C5" Opacity="0.35"/>
</StackPanel.Background>
<TextBlock Text="{Binding Title.Text, Converter={StaticResource RssTextTrimmer}}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" Foreground="White" FontSize="30"/>
<TextBlock Text="{Binding Summary.Text, Converter={StaticResource RssTextTrimmer}}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" Foreground="#99FFFFFF"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
I Have used this sample: http://code.msdn.microsoft.com/wpapps/RSS-Reader-Sample-1702775f

Find parentitem in wpf-treeview

I hoped the answer to my previous question whould help me with this one, but it didn't. The initial situation is pretty much the same:
<TreeView ItemsSource="{Binding Groups}" Name="tvGroups" AllowDrop="True">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Participants}">
<StackPanel Orientation="Horizontal" Drop="tvDrop" Tag="{Binding .}">
<TextBlock Text="{Binding Name}" />
<Button Tag="{Binding .}" Click="Button_Click_2">
<Image Source="Resources/cross.png" />
</Button>
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Alias}" />
<Button Tag="{Binding .}" Name="btnDeleteParticipants" Click="btnParticipants_Click" >
<Image Source="Resources/cross.png" />
</Button>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
private void btnParticipants_Click(object sender, RoutedEventArgs e)//Probanten aus Gruppe entfernen
{
Participant p = ((sender as Button).Tag as Participant);
if (p == null) return;
//TODO: Raus bekommen in welcher Gruppe ich löschen will
}
I want to remove Participant p from a Group by clicking the button(btnDeleteParticipants). I tried something like this one:
Control c = sender as Control;
while (!(c is TreeViewItem))
c = (c.Parent) as Control;
But this didn't work (don't ask why, I'm not sure). I could find the Group by checking if it contains the Participant(bound to btnDeleteParticipants.Tag), but this would disallow participants to be in more than 1 group.
So, any ideas how to get the right Group?
Edit:
Groups = new ObservableCollection<Group>();
Participants = new ObservableCollection<Participant>();
Are Groups and Participants ObservableCollection objects?
Try using this:
static TObject FindVisualParent<TObject>(UIElement child) where TObject : UIElement
{
if (child == null)
{
return null;
}
UIElement parent = VisualTreeHelper.GetParent(child) as UIElement;
while (parent != null)
{
TObject found = parent as TObject;
if (found != null)
{
return found;
}
else
{
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
}
return null;
}
Also, try using the DataContext to get the participant and set the Tag to the TemplatedParent.
<Button Tag="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
Then on click
private void btnParticipants_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var p = button.DataContext as Participant;
if (p == null) return;
var t= FindVisualParent<TreeViewItem>(button); // get the Participants TreeViewItem
if (t == null) return;
var groupTreeItem = FindVisualParent<TreeViewItem>(t); // get the groups TreeViewItem
if (groupTreeItem == null) return;
var group = groupTreeItem.DataContext as Group;
group.Participants.Remove(p);
}

Categories