How to access a TextBlock within a ListBox with C# - 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.

Related

WPF -How to access the fields present in a template

Let me explain so I have a wpf application I used a listBox with a template. This template contains a TextBlock and a ComboBox. When running the application, everything goes well, my list is initialized correctly. But then I would like to retrieve the values ​​of my TextBlock and my comboBox and I don't understand how I can achieve this.
I am attaching the part of my XAML code that deals with this listBox :
<ListBox x:Name="ListBoxEnv" Grid.Row="1"
d:ItemsSource="{d:SampleData ItemCount=5}" Width="460"
SelectionChanged="ListBoxEnv_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TxtBlockEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
Text="{Binding EnvName}"/>
<ComboBox x:Name="ComboBoxEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding EnvListValue}"
Margin="100,2,0,2" Width="200"
SelectionChanged="ComboBoxEnv_SelectionChanged"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The EnvName property is readonly because it is bound to TextBlock, so you can ignore it. Change binding to: Text="{Binding EnvName, Mode=OneTime}" to save the app resources.
However to extract selected environment in every combo in the list you need to add to ComboBox template: SelectedItem={Binding SelectedEnv} and add new property to SampleData
for example
public MyEnvironmentClass SelectedEnv {get; set;}

How to collapse contents of a databound ListBoxItem when a button is clicked in WPF MVVM

I have a ListBox in my WPF MVVM app using the following code:
<GroupBox Grid.Column="0" Margin="0,0,0,-58">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Center"
Margin="0,0,0,8"
FontWeight="Bold"
Text="{x:Static p:Resources.AvaliableLEDsLabel}" />
<ListBox Name="AvailableLEDsListbox" SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
ItemTemplate="{StaticResource DataTemplateListBoxItem}"
ItemsSource="{Binding AvailableLeds}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
>
<ListBox.GroupStyle>
<StaticResource ResourceKey="StyleListBoxGroup" />
</ListBox.GroupStyle>
</ListBox>
</DockPanel>
</GroupBox>
This displays grouped lists of devices, with LEDs under them. The DataTemplate is the following:
<GroupStyle x:Key="StyleListBoxGroup">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Command="{Binding HideGroupCommand}">X</Button>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Left"
FontWeight="Bold"
Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<DataTemplate x:Key="DataTemplateListBoxItem">
<TextBlock x:Name="LedId" Text="{Binding LedId}"/>
</DataTemplate>
I would like to make the X button in the header hooked up to the HideGroupCommand toggle the hiding of all the items under that particular header. How would I go about doing this? Thanks in advance.
You have few options.
First one :
You would need to have a property in your view model something like 'ListBoxVisibility' then u would bind that property to your UI. In command text u just changed visibility property of that property in view model- so u have it reflected on UI. This visibility property can be of type 'bool' , or 'Visibility' or whatever. Only if it's type of Visibility u don't need converter when binding.
NOTE : Some people use it - even though it kinda goes out of general principel of MVVM patter. But sometimes u have to do it.
Second
If wanna stick to MVVM , then u need to fully separate your UI from your viewmodel. Create click event and change visibility.

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

Accessing a TextBlock which is contained inside a ListBox

I have a textblock which is inside a listbox and I am trying to write an if statement which is dependant on the contents of this textblock. I am trying to get the data from the TextBlack which I have named "category1" however when I try to write my if statement I am getting a message which just says
"the name category1 does not exist in the current context"
I tired moving that TextBLock out of the ListBox and it works fine but wont work while its inside there. Does anyone know how to reference this textblock.
Here is the my XAML code
<ListBox x:Name="HINList" Margin="0,300,-12,0" ItemsSource="{Binding Details}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding HINNumber}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding CategoryLetter}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="category1" Text="{Binding Category1}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="{Binding Category2}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="{Binding Category3}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Assuming you're writing your if statement in the code behind file, wouldn't something like:
if(((WhateverTypeIsInDetailsCollection)HINList.SelectedItem).Category1 == something) {
// then do whatever you want
}
As Russell pointed out there is a category1 item for every entry in the list. I assume you wanted to do something with the selected item.
This is due to xaml namescopes. The names inside a DataTemplate are in a different namescope than outside, that's why you can't access them (what #Russell pointed is part of why it's done this way).
I think that you want to access that field for the "Category1" property on the selected item of the HINList ListBox that is bound to the Details collection. What you can do is set the binding on the Category1 to be two way, and bind the SelectedItem of the ListBox to a Detail item like so:
xaml:
<ListBox x:Name="HINList" ItemsSource="{Binding Details}"
SelectedItem={Binding SelectedDetailItem, Mode=TwoWay}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding Category1, Mode=TwoWay}" TextWrapping="Wrap" .../>
<!-- the other fields -->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
code-behind
if(SelectedDetailsItem.Category1==...)
{
....
}
Hope this helps :)

ListBox ItemsSource Binding doesn't work

I'm developing a Windows Phome application. I have the following ListBox on a page:
<ListBox Margin="10,10,8,8" x:Name="WallList">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="ListBoxItemLayout" Background="Transparent" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.33*"/>
<ColumnDefinition Width="0.77*"/>
</Grid.ColumnDefinitions>
<Image HorizontalAlignment="Left" Margin="0" Source="{Binding ImagePath}" Height="200"/>
<StackPanel Margin="5,0,0,0" Grid.Column="1">
<TextBlock x:Name="Name" TextWrapping="Wrap" Text="{Binding Name}" Style="{StaticResource PhoneTextTitle2Style}"/>
<TextBlock x:Name="Comment" Margin="0,5,0,0" TextWrapping="Wrap" Text="{Binding Comment}" Style="{StaticResource PhoneTextNormalStyle}" Height="130"/>
<TextBlock x:Name="When" TextWrapping="Wrap" Text="{Binding When}" Style="{StaticResource PhoneTextTitle3Style}" VerticalAlignment="Bottom"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm using this to fill the ListBox on Loaded event:
this.WallList.ItemsSource = StartingWall.GetWallPosts();
And now I want to add more items programmatically when the user write down some text on a TextBox and click on a button. I want to place this text on Comment field.
I'm gooing to fill the rest fields with default data.
My question is:
How can I add more items to WallList ListBox?
Someone has suggested to do the following:
public ObservableCollection<WallPostEntry> MyWallPosts {get;set;}
// Initialize MyWallPosts to whatever
MyWallPosts.Add(new WallPostEntry("new entry"));
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}">
But Binding ListBox ItemsSource doesn't work for me. I'm initializing MyWallPosts on constructor, just before InitializeComponent();, like this:
public Wall()
{
MyWallPosts = StartingWall.GetWallPosts();
InitializeComponent();
}
Any advice?
Thanks.
I see a couple wierd things:
first, you're using the itemssource binding in one place, but explicitly setting it in another? setting something in code will override/undo any bindings, so that could cause a problem (but it looks like you're setting it to the same thing so that shouldn't make a difference, but i'd remove the this.WallList.ItemsSource = StartingWall.GetWallPosts(); call entirely, and leave the ItemsSource="{Binding MyWallPosts}" in the xaml. the point of using bindings is to get rid of this kind of code)
second, you're setting mywallposts and using a binding, but not setting the datacontext on your object itself? simplest in your example would be to just add one line to your constructor:
public Wall()
{
DataContext = this;
MyWallPosts = StartingWall.GetWallPosts();
InitializeComponent();
}
My next suggestion would be to simplify until it works. leave the listbox but comment out all of the item/data templating to make sure that you don't have a bug in your template
Could he just add
a DataContext property to this:
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}">
so:
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}" DataContext="{Binding MyWallPosts}">
Would there be any way of setting the dataContext declarativelly?
tks,
Oscar

Categories

Resources