Binding data in C# and XAML? - c#

I'm trying to use binding with C# and a XAML SemanticZoom control in my Metro app, but honestly I'm at a loss as to how to do it. Here's the XAML code I've gotten so far by piecing together from questions, articles, etc:
<SemanticZoom x:Name="boardZoom" Height="626" Margin="10,132,10,0" VerticalAlignment="Top">
<SemanticZoom.ZoomedInView>
<GridView IsSwipeEnabled="True" x:Name="ItemsGridView">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0"
HorizontalAlignment="Left" Background="White">
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="200" Height="300"
FontFamily="Global User Interface" FontSize="40" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Image Source="{Binding Image}" Height="60" Width="60"
VerticalAlignment="Center" Margin="0,0,10,0" Visibility="{Binding isImage}" />
<TextBlock Text="{Binding Category}" TextWrapping="Wrap" Width="200"
FontFamily="Global User Interface" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</SemanticZoom.ZoomedInView>
<!--Didn't include SemanticZoom.ZoomedOutView since I'm still trying to get the ZoomedIn one working first-->
</SemanticZoom>
And my C# code:
List<PinStore.pin> pins = PinStore.CopyFromStream(response.GetResponseStream()); //returns a list of PinStore.pin objects, which have name, type, Image, isImage, and Category objects
System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn> toSource = new System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn>(); //should I be using ObservableCollection or something like List<> here?
foreach (PinStore.pin pin in pins)
{
SemanticZoomed.ZoomedIn toAdd = new SemanticZoomed.ZoomedIn(); //class with Title, Image, isImage, and Category objects
if (pin.type == "text")
{
toAdd.Title = pin.name;
toAdd.Image = null;
toAdd.isImage = Visibility.Collapsed;
toAdd.Category = pin.category;
}
toSource.Add(toAdd);
}
ItemsGridView.DataContext = toSource;
I've not had much experience in XAML/C#, and zero experience with binding. I'm not getting any errors, but I've noticed that if I replace ItemsGridView.DataContext = toSource; with ItemsGridView.ItemsSource = toSource; a blank stackpanel shows up in the GridView, and I can't seem to find a way to fill that with the Title and Category values I specify. Thanks!

Well you should first consider creating a ResourceDictionary so you can save your item style. Then you can set the ItemStyle to the Resource Dictionary.
But regardless you need to do: ItemsGridView.ItemsSource = toSource; If you do not choose to Bind the toSource in the GridView xaml.
Also make sure the SemanticZoomed.zoomedIn object implements the INotifyPropertyChanged interface, And calls the event properly. And make sure the Title, Image, Category, etc are public properties that call the event when edited. and Also you need make sure pin.Text is an actual value. {Making sure}.
If you want to learn more about data binding check out how they do it in C# & XAML with Windows 8 {Should be the same thing}:
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx

Related

Data Binding for nested controls

I want to do search inside some books, then result of each book appears in separate item of pivot control. each one is represented by a separate LongListSelector control inside that PivotItem. Now I want to know should I assing ItemsSource for LongListSelector or for its parent which is a Pivot?
There is a dictionary for all books:
private Dictionary<string, List<Model>> ItemResources = new Dictionary<string, List<Model>>();
and a List<Model> for each book, which will be saved as a value inside ItemResources above.
this is what I do:
foreach (var translation in ItemResources)
{
PivotItem pivotItem = new PivotItem
{
Header = translation.Key
};
LongListSelector lls = new LongListSelector
{
HideEmptyGroups = false,
IsGroupingEnabled = false
};
lls.ItemTemplate = Resources["template"] as DataTemplate;
lls.ItemsSource = translation.Value;
pivotItem.Content = lls;
ResultPivot.Items.Add(pivotItem);
}
and the template is a reusable DataTemplate which I redproduce it for each longlistselector inside each pivotItem of the ResultPivot:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="template">
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="455" Margin="3,20,3,0">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
<TextBlock Text="{Binding Number}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
</StackPanel>
<StackPanel Height="Auto" VerticalAlignment="Top" HorizontalAlignment="Left" Width="455" Margin="3,0,3,20">
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
The problem is that nothing appears on the screen after running. I saw in debugging, that the values are there, but it seems something is wrong with data binding. How can I solve it? thanks
(this is a Windows Phone 8 App, but because the concept is the same for WPF and its wide community I added it too)
The UI has currently no way of knowing when the source changes. You need to either use an ObservableCollection or implement the INotifyPropertyChanged interface to properly notify the UI when the source changes.

Ungrouped Long List Selector

Okay, So I am trying to bind a list of objects with a DisplayName property to a long list selector.
XAML Code
<phone:LongListSelector x:Name="lls_TemplateFields" HorizontalAlignment="Left" Width="450" Grid.Row="2" Height="400" LayoutMode="List" Background="#FF9E9D9D" IsGroupingEnabled="False">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding DisplayName}" Foreground="Black" FontSize="24"/>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
C# Code
List<AttributeDefinition> m_SelectedAttributes = new List<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
My Class AttributeDefinition contains a property for DisplayName. If I group the the list using a group key then the list will show up, however I cannot get just a plain list of items to show up. Like a listbox in WPF C#.
I am using this list to represent a list of chosen AttributeDefinitions from another list that shows all the AttributeDefinitions grouped alphabetically by their DisplayName property, and the Display Value is Binded to the DisplayName Property like shown below...
XAML
<phone:LongListSelector x:Name="lls_AttributeList" HorizontalAlignment="Left" Height="450" VerticalAlignment="Top" Width="450" HideEmptyGroups="True" IsGroupingEnabled="True" SelectionChanged="SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="2">
<TextBlock Text="{Binding DisplayName}" Foreground="{StaticResource PhoneChromeBrush}" FontSize="24"/>
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
<phone:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Grid Width="50" Height="50" HorizontalAlignment="Left" VerticalAlignment="Center" Background="Blue">
<Border BorderThickness="4">
<TextBlock Text="{Binding Key}" Foreground="White" FontSize="38" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>
</phone:LongListSelector>
C#
List<AttributeKeyGroup<AttributeDefinition>> DataSource = AttributeKeyGroup<AttributeDefinition>.CreateGroups(AttributeData,
Thread.CurrentThread.CurrentUICulture,
(AttributeDefinition aDef) => { return aDef.Type; },
true);
lls_AttributeList.ItemsSource = DataSource;
This list works just fine. And the data in the background is functioning properly, because as I select items from the total list of attributedefinitions they are removed from the LongListSelector and added to the LongListSelector of the selected lists Itemssource
For further inquiry into more code surrounding this User Control please feel free to ask I will disclose as much code as I can without breaking my non-disclosure agreement with my work. Thank you for taking the time to read and possibly help. Much appreciated.
List<AttributeDefinition> m_SelectedAttributes = new List<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
because you just instantiated this list and binding it right away? How about adding some items into the list
There are two answers to this. I have tried both and both work.
[1] You have to set the LongListSelector.ScrollTo(object) to the first object of your list when you update the data if the list has 1 or more items. Such as...
lls_TemplateFields.ItemsSource = m_SelectedAttributes;
if(m_SelectedAttributes.Count > 0)
{
lls_TemplateFields.ScrollTo(m_SelectedAttributes[0]);
}
[2] The proper way to fix this is to use ObservableCollections which work better with DataBinding and the WP8 WPF SDK UI to update on adding objects to the ObservableCollection.
ObservableCollection<AttributeDefinition> m_SelectedAttributes =
new ObservableCollection<AttributeDefinition>();
lls_TemplateFields.ItemsSource = m_SelectedAttributes

Create control instance in WPF

I want to load multiple images inside a wrappanel, for each image I show a thumbnail and some image details with this code
<Border BorderThickness="1" BorderBrush="#FFD0D1D7" Padding="5" Margin="10,10,0,0">
<StackPanel Orientation="Horizontal">
<!--image and dimensions-->
<Grid Width="88" Height="55">
<Image Source="C:\img1.jpg" Width="88" Height="55"/>
<TextBlock Background="#B2000000" Foreground="White" Height="16" TextAlignment="Center" VerticalAlignment="Bottom">1280x1024</TextBlock>
</Grid>
<!--name, type and size-->
<StackPanel Orientation="Vertical" Margin="5,0,0,0" VerticalAlignment="Center">
<TextBlock Margin="1" Foreground="#FF787878">img13.jpg</TextBlock>
<TextBlock Margin="1" Foreground="#FF787878">Type: JPEG</TextBlock>
<TextBlock Margin="1" Foreground="#FF787878">Size: 321 KB</TextBlock>
</StackPanel>
</StackPanel>
</Border>
But the images are loaded at runtime, and I need some way to create instances of the above code to show the image, dimensions, name, type and size
I tried this solution https://stackoverflow.com/a/4991028/962284
StringBuilder sb = new StringBuilder();
// use xaml to declare a button as string containing xaml
sb.Append(#"<Border BorderThickness='1' BorderBrush='#FFD0D1D7' Padding='5' Margin='10,10,0,0'>
<StackPanel Orientation='Horizontal'>
<!--image and dimensions-->
<Grid Width='88' Height='55'>
<Image Source='C:\img1.jpg' Width='88' Height='55'/>
<TextBlock Background='#B2000000' Foreground='White' Height='16' TextAlignment='Center' VerticalAlignment='Bottom'>1280x1024</TextBlock>
</Grid>
<!--name, type and size-->
<StackPanel Orientation='Vertical' Margin='5,0,0,0' VerticalAlignment='Center'>
<TextBlock Margin='1' Foreground='#FF787878'>img13.jpg</TextBlock>
<TextBlock Margin='1' Foreground='#FF787878'>Type: JPEG</TextBlock>
<TextBlock Margin='1' Foreground='#FF787878'>Size: 321 KB</TextBlock>
</StackPanel>
</StackPanel>
</Border>");
FrameworkElement thumb = (FrameworkElement)System.Windows.Markup.XamlReader.Parse(sb.ToString());
ThumbnailContainer.Children.Add(thumb);
but I get the following error
I also tried with styles, but styles doesnt support multiple parameters (to specify the textblocks: dimensions, size, name, type and size) just "TemplateBinding Tag" for 1 value
What can I do to create instances of the first code to show multiple images at runtime?
Wow. That so looks like the hard way to do things. Time to embrace WPF and XAML.
I had a post about this exact same thing that wasn't quite finished. I took time to finish it for you. I even used your XAML snippet (well, a modified version of it) in the example, just for you.
http://www.wpfsharp.com/2012/10/23/displaying-images-from-a-folder-with-details-in-wpf/
Clemens is correct in his comment to use an ItemsControl.
Yes your approach is wrong and you should be doing this some other way but to get your code snippet to work try adding xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" to your Border element in the string you are building. I suspect that is the error.

How to access a TextBlock within a ListBox with C#

For most of you, this might be an easy question, but I am a C# beginner (coming from VB) and would like to progam a Windows Phone App.
The question is: How can I access the TextBlock "LineOne" from code to change its width? For the page title, it works perfect with this (on orientation change):
this.PageTitle.Text = "Portrait";
However, something like this:
this.LineOne.width= "50";
won't work.
Why?
My XAML looks like this (almost the default data bound app from Visual Studio Express):
<!--TitlePanel -->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="PageTitle" Text="Bundesliga" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel -->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="ListboxPanel" Margin="0,0,0,17" Width="432" Orientation="Horizontal">
<TextBlock x:Name="LineOne" Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextNormalStyle}" Width="40" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Thanks for your help!
You have to access the TextBlocks inside the listbox.
Something like:
TextBlock textblock = ListboxPanel.Items[index] as TextBlock;
textblock.Width = 50
IEnumerable<TextBlock> listtb = ListboxPanel.Items.TypeOf<TextBlock>();
The name can't be resolved as belonging to this as it belongs to the datatemplate. You can't refer to an item within a template (from outside that template) as there could be multiple items with that name and names must be unique.
If you are trying to change the style of the selected item you will likely find a better solution to be to use different visual states to represent this.
If you are trying to access a property which relates to the bound viewmodel you can cast the sender to the type of the viewmodel and access it's properties directly.

Silverlight how to use data template selector for listbox items when binding to complex collections

I have been looking at samples of DataTemplateSelectors for sivleright and from the examples I have seen the values being returned and evaluated within the Content Control seems to be a single property that has been returned to the listbox from a collection.
Does anyone have any suggestions on how this is addressed when returning a complex collection to a listbox item source? By complex collection I mean an observable collection named "Result" and within that a List collection exists titled "Names" ? I need to trigger the data template selector from a property found within the List collection and not properties from the result collection. i.e. List collection may contain the properties name, sex, age and I want to use the sex property as the trigger whereas Result may contain properties like property, time, or notes and I do not need to use these to invoke the template trigger.
Thank you for any suggestions.
Update with code example
Working through this where I am getting stuck is in the binding of my listbox item custom template.
Here is the listbox control xaml
<ListBox HorizontalAlignment="Stretch" ItemsSource="{Binding SearchResults[0].Results, Mode=TwoWay}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderBrush="#66C4C4C4" >
<ListBox.ItemTemplate>
<DataTemplate>
<qr:SearchResultItemControl />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
qr:SerarchResultItemContol xaml is the custom lsitbox item I currently have defined this user control contains the following elements
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="92.915"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Fill="#FFF4F4F5" Margin="5,6,7.5,0" RadiusY="4" RadiusX="4" Stroke="Black" Height="52" VerticalAlignment="Top"/>
<TextBlock Margin="4,3,76,0" TextWrapping="Wrap" FontSize="13.333" Height="17" VerticalAlignment="Top" Grid.Column="1" d:LayoutOverrides="VerticalAlignment" FontWeight="Bold" Text="{Binding Type, Mode=TwoWay}"/>
<TextBlock Margin="8,15,10.5,0" TextWrapping="Wrap" FontSize="9.333" Height="35" VerticalAlignment="Top" d:LayoutOverrides="VerticalAlignment" Text="image placeholder" TextAlignment="Center"/>
<TextBlock Margin="3,97,4,0" TextWrapping="Wrap" FontSize="12" Height="17" VerticalAlignment="Top" Text="{Binding Relevance, Mode=TwoWay}"/>
<TextBlock Margin="3,75,20,0" TextWrapping="Wrap" FontSize="12" Height="18" VerticalAlignment="Top" Width="70" Text="{StaticResource txtRelevance}"/>
<TextBlock Grid.Column="1" Margin="4,24,5,6" TextWrapping="Wrap" FontSize="12" RenderTransformOrigin="0.5,0.5" Text="{Binding HitContext, Mode=TwoWay}"/>
</Grid>
Running this the control works fine I see my results. What I would like to do is control what data ListboxItem template is loaded based upon the value returned in Type binding.
The itemsSource is being returned from my view model SearchResults Collection which is being generated from a WcF service.
VM code for bindable collection:
public ObservableCollection<QueryResponse> SearchResults
{
get
{
return this._SearchResults;
}
private set
{
if (this._SearchResults == value)
return;
// Set the new value and notify
this._SearchResults = value;
this.NotifyPropertyChanged("SearchResults");//this binds to UI search returns
}
}
the searchresult collection is comprised of the following properties
SearchResult
string QueryText
string QueryTime
Results
string TotalMatches
...
The Results collection that is returned within SearchResult contains:
string Content
string HitContext
string ID
string relevance
string Type
What I am trying to accomplish is to have the DataTemplateSelection triggered off of the Type value returned from the results collection.
Any suggestions would be appreciated.
Found my answer based upon the following solution from codeproject
This solution provided a very basic and straight forward DataSelection template that fit my needs.
With regards to accessing a complex collection vs. a flat collection I cast my item object against the nested collection and from there able to access the appropriate properties.

Categories

Resources