Dynamically add TextBlock to StackPanel - c#

So I'm developing a Windows Phone 8 app in C# using MVVM pattern. I have a screen where the layout needs to be like this:
TextBlock
Image
TextBlock
TextBlock
If the Dynamic list of buttons.count is > 1 insert a TextBlock here
Dynamic list of buttons
TextBlock
TextBlock
So I've been trying to set up this in xaml code, and it looks like this:
<StackPanel Orientation="Vertical">
<TextBlock Margin="20,0,20,0" TextWrapping="Wrap" Foreground="#c8d75a" Text="{Binding Title, Mode=TwoWay}" Height="46"></TextBlock>
<Image Margin="20,0,20,0" Source="{Binding ImageLink}" Height="200"></Image>
<TextBlock Margin="20,0,20,0" TextWrapping="Wrap" Foreground="#7e9d83" Text="{Binding subTitle, Mode=TwoWay}" Height="46"></TextBlock>
<TextBlock Margin="20,0,20,0" TextWrapping="Wrap" Foreground="#7e9d83" Text="{Binding Description, Mode=TwoWay}" Height="46"></TextBlock>
<ItemsControl ItemsSource="{Binding RelatedLinks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="20,0,20,0" Foreground="#c8d75a" Text="{Binding Text, Mode=TwoWay}" Height="46">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cm:ActionMessage MethodName="OpenLink">
<cm:Parameter Value="{Binding Href}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Margin="20,0,20,0" TextWrapping="Wrap" Foreground="#7e9d83" Text="{Binding Creator, Mode=TwoWay}" Height="46"></TextBlock>
<TextBlock Margin="20,0,20,0" TextWrapping="Wrap" Foreground="#7e9d83" Text="{Binding PubDate, Mode=TwoWay}" Height="46"></TextBlock>
Now everything is working as it should except the part on my list that says "If the Dynamic list of buttons.count is > 1 insert a TextBlock here".
Let me try to explain that further. My {Binding RelatedLinks} is a bind to a ObservableCollection<RelatedLink> where RelatedLink is an object with two strings Href and Text.
So if my ObservableCollection of RelatedLinks is bigger then 1 i want to have a title text placed above this ItemsControl list. How can i achieve this?

ObservableCollection implements INotifyPropertyChanged and notifies about changes to Count, so you can bind to it. To show or hide a TextBlock, you would change its Visibility like this:
<TextBlock
Visibility="{Binding RelatedLinks.Count, Converter={StaticResource CountToVisibilityConverter}}"
... />
What is left is to write the CountToVisibilityConverter and add it to resources. Its Convert method would be something like:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value > 1 ? Visibility.Visible: Visibility.Collapsed;
}
An alternative approach would be to add a property bool TextVisible to your ViewModel and update it every time you update the ObservableCollection, then use a standard BoolToVisibilityConverter.

Related

WPF Binding TextBlock value to display SelectedItem in ComboBox

I have a ComboBox and a couple of TextBlock fields.
I want to display the properties of a SelectedItem from the ComboBox on those Textblock's. Image
So that when I choose one of multiple user's the properties in the TextBlock will update to those of the SelectedItem. I have found an example, although it is using silverlight, and does not work entirely.
<ComboBox Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Bottom"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Left"
Margin="0"
Height="40"
Name="ComboBox"
ItemsSource="{Binding UserModels}"
SelectedItem="{Binding EnteredUserModel, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}"
Style="{StaticResource ResourceKey=ComboBoxItemTextBlock}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
<TextBlock Grid.Row="1"
Grid.Column="0"
Margin="0 10 0 10" >
<Run Text="{DynamicResource firstName}" />
<Run Text=": " />
<Run Text="{Binding ElementName=ComboBox, Path=SelectedItem, UpdateSourceTrigger=PropertyChanged}" />
</TextBlock>
This is what I've tried. I added Name to the ComboBox so that I can access it's SelectedItem in my TextBlock. I need to get the SelectedItem.firstname, etc. At this stage i can only access the entire objects.
Am I missing some useful binding?
In order to show the FirstName property of the SelectedItem, just use an appropriate property path, i.e. SelectedItem.FirstName:
<Run Text="{Binding ElementName=ComboBox, Path=SelectedItem.FirstName}" />
or, since SelectedItem is bound to an EnteredUserModel property in your view model:
<Run Text="{Binding Path=EnteredUserModel.FirstName}" />
Setting UpdateSourceTrigger=PropertyChanged is not necessary. It has no effect in a OneWay Binding.
You're getting the EnteredUserModel-Object, because that's the selected item of the ComboBox. If you want the displayed text you must bind to the FirstName-Property.
Alternatively you can bind to EnteredUserModel.FirstName in your TextBox

ListBox Value Display in Windows Phone 8

I am trying to bind the observable collection with a ListBox and displaying the data on UI (Windows Phone 8.0).
My Listbox have four textblock for four property,
<ListBox x:Name="allListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Style="{StaticResource txtBlockStyleDate}" Text="{Binding Date}"></TextBlock>
<TextBlock Style="{StaticResource txtBlockStyle1}" Text="{Binding TypeOfApproval}"></TextBlock>
<TextBlock Style="{StaticResource txtBlockStyle2}"
Text="{Binding TypeOfRequest}" />
<TextBlock Style="{StaticResource txtBlockStyle3}" Text="{Binding Status}"/>
<TextBlock Height="30"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
all the objects in observable collection are showing fine, but when any of the property does not have any value, its text block is still there, and its space is kind of visible, which gives the bad impression over UI.
Can you suggest what should i do, when any property is blank, textblock related to that should not eat any height and next textblock should take space of it.
I am attaching an image, see after testing blank space is visible, coz its property is null, i want to remove this space.
You are going to need an IValueConverter, basically the idea is you do this:
... insert ...
<ListBox.Resources>
<VisibilityConverter x:Key="VisibilityConverter"/>
</ListBox.Resources>
... change ...
<TextBlock Style="{StaticResource txtBlockStyleDate}" Visibility="{Binding Date, Converter={StaticResource VisibilityConverter}}" Text="{Binding Date}"/>
Within your IValueConverter implementation, you just see if the property is null or empty. If it is you just return Visibility.Collapsed
You need to use a Visibility converter for this!
If your bound data is text, a StringToVisibilityConverter would be fine.
An example on how to do this can be found here: http://www.smallandmighty.net/blog/using-value-converters-to-change-the-visibility-of-a-control

Windows 8 store app: How dynamically change Binding in ListViewItem

I have created a common control for listView and I want to change the content of each item in the listView. Something like DisplayMemberPath but I need to send two values ​​that are not the same for any one screen.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Property1}"/>
<TextBlock Text="{Binding Setter2}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
and on the next screen I want something like this
<TextBlock Text="{Binding SuperNewProperty}"/>
<TextBlock Text="{Binding Setter2xyz}"/>
How do I create a control which has variable binding like:
<TextBlock Text="{Binding {Binding MySpecificValue}"/>
This is obviously a stupid thing, but it best describes what I want to do.
For completion:
Ok i have some module Employes.xaml
where call, my control with some dependency properties as itemSource and prop1, prop2(I want to use both, like display member path).
ItemSource is IEnumerable from DB and contains 2 columns: employeName, employNumber, this will be displayed on the listView
<control:listViewMyControl itemSource ="{Binding employes}" prop1="employeName" prop2="employNumber" />
but when i have modul Cities.xaml
I need binding prop1, prop2 to another column name, cityName, cityRank or whatever
<control:listViewMyControl itemSource ="{Binding cities}" prop1="cityName" prop2="cityRank " />
The problem comes when I want to display two different types of listviewitems for listview
// my user control listViewMyControl
<ListView x:Name="listView1">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding employeName}"/>
<TextBlock Text="{Binding employeNumber}"/>
<TextBlock Text="{Binding cityName}"/>
<TextBlock Text="{Binding cityRank}"/>
// but i want only something like display member path for two labels, input modules may be more (employes, cities, cars, stations, .....) something like this
<TextBlock Text="{Binding {Binding MySpecificValue}"/>
<TextBlock Text="{Binding {Binding MySpecificValue2}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Thanks in advance.

Dynamically control the number of buttons in WPF

I'm working with WPF recently. Now, i'm facing a problem.
I have a button "ADD", every time click on this will add a new row with some contents. Those contents are shown below-
<TextBox Text="{Binding Name}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding City}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding Age}" Margin="10,10" Height="20"></TextBox>
<TextBox Text="{Binding Count}" Margin="10,10" Height="20" ></TextBox>
<Button Content="M1" Margin="10,10" Height="20"/>
<Button Content="M2" Margin="10,10" Height="20"/>
<Button Content="M3" Margin="10,10" Height="20"/>
</WrapPanel>
</Grid>
Here, at the end there are three buttons M1,M2,M3. But, I don't need this all three buttons every time. I may need only M1 or only M2 or only M3 or M1,M2 etc.
How can I do this in c#?
Actually i don't even know, am i in the right way?
Thanks in advance.
I would highly recommend looking into the MVVM design pattern when working with WPF
That said, I would bind my XAML to an ObservableCollection<SomeObject>, and clicking the AddButton would add a new SomeObject to the ObservableCollection. This would make the UI automatically add the new row when the collection gets updated, and SomeObject could have properties for IsM1Visible, IsM2Visible, and IsM3Visible which determines which buttons are visible.
For example,
Class SomeObject would have
string Name;
string City;
int Age;
int Count;
bool IsM1Visible;
bool IsM2Visible;
bool IsM3Visible;
The XAML would look something like this:
<ItemsControl ItemsSource="{Binding SomeCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBox Text="{Binding Name}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding City}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding Age}" Margin="10,10" Height="20"></TextBox>
<TextBox Text="{Binding Count}" Margin="10,10" Height="20" ></TextBox>
<Button Content="M1" Visibility="{Binding IsM1Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
<Button Content="M2" Visibility="{Binding IsM2Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
<Button Content="M3" Visibility="{Binding IsM3Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the Add Button's Click event would look something like this:
void AddButton_Click(object sender, EventArgs e)
{
var newItem = new SomeItem
{
Name = "Something",
City = "Something",
Age = 30,
Count = 2,
IsM1Visible = true,
IsM2Visible = false,
IsM3Visible = true
};
SomeCollection.Add(newItem);
}
You could use DataBinding if the amount of buttons is dependent on the size of a list/collection.
<ItemsControl ItemsSource={Binding Ms}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}" Command={Binding ThingToDoWhenClickedCommand}/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This will generate exactly the amount of buttons that is in the Ms collection/List that is in the DataContext.
You can just add the buttons through your code-behind files and put an if structure around the buttons to determine what button should be loaded.
Are you using MVVM?
If so then this is easy. Just create a ButtonViewModel object that represents one of your buttons and expose an ObservableCollection of them from your main ViewModel.
In your view just have a ListView, or just an ItemsControl bound to the collection, and a DataTemplate that turns your ButtonViewModel into a button.
When the user clicks the Add button, add a new ButtonViewModel to your collection and the view will update itself to match.
First, let create a view model for a row. In that model you will have 3 bool properties, IsButton1Visible, IsButton2Visible, IsButton3Visible, or something like that with all properties you need to do binding on your row.
Second, your scenario is that when you click Add, new row will be added. So you have a list of Row_View_Model. On AddCommand, you will at a new Row_View_Model into the list. Here you have full control on what button you want to show.

Getting Listbox Value WP7

how to get value from the textblock , which is present in listbox ....
here is the code xaml :
<ListBox Height="707" HorizontalAlignment="Left" Margin="12,0,0,0" Name="listBox1" VerticalAlignment="Top" Width="456" Background="White" Foreground="#FF09090C" ItemsSource="{Binding}" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Name="textBlock3" FontSize="18" Foreground="Blue" Margin="2" Text="{Binding Title.Text}" TextWrapping="Wrap" />
<TextBlock FontSize="16" Foreground="Gray" Margin="2" Text="{Binding Summary.Text}" TextWrapping="Wrap" />
<TextBlock FontSize="1" Foreground="Gray" Margin="2" Text="{Binding Id}" TextWrapping="Wrap" Visibility="Collapsed" />
<Button Name="h1" Content="Press" Height="10" Width="40"></Button>
<TextBlock Foreground="Gray" Margin="2" Text="________________________________________________________________________________________" FontSize="8"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You don't get the value directly from the TextBlock.
Instead what you do is bind the SelectedItem to a property on your viewmodel. To get the value of the TextBlock directly would violate the priciples of MVVM (if you are using that pattern). The viewmodel presents the data, it has no clue how that data is being rendered to the UI. IOW it has no idea there are three TextBlocks.
<ListBox Height="707" SelectedItem={Binding MyViewModelProperty} >
... etc ...
This means that every time the selected item is changed, the new value will be populated into the bound property on the viewmodel. All you have to do then is access that object - it's as easy as that. This means you may also possibly be able to get rid of your SelectionChanged event hookup, depending on what it is doing.
However if you insist on getting the instance of the template used to present any particular data item in a list control, then this is the way to do it programmatically:
myListBox.ItemContainerGenerator.ContainerFromItem(myDataItem);
This will return you the StackPanel and its contents, you can then either use FindName() or just enumerate the child controls to find the one you are interested in.
FrameworkElement element = myListBox.ItemContainerGenerator.ContainerFromItem(myDataItem) as FrameworkElement;
if (element != null)
FrameworkElement child = element.FindName("myChildName");

Categories