I have a binded treeview that displays one of the properties (namely, the displayname) of the treeviewitem (which are custom viewmodel's of an object).
Here is the associated xaml:
<local:ExtendedTreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubOrganLocations}">
<TextBlock Text="{Binding OrganDisplayName}" >
</TextBlock>
</HierarchicalDataTemplate>
</local:ExtendedTreeView.ItemTemplate>
What I want is to be able to display another property next to the display name in parenthesis.
so instead of the treeview looking like this:
Root
-sub node1
--subsub node1
-sub node2
I want it to look like this:
Root (Type1)
-sub node1 (Type2)
--subsub node1 (Type 3)
-sub node2 (Type 1)
How can I accomplish this? Using multi-binding?
Try this:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="{YourBindingHere}" />
<Binding Path="{YourBindingHere}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
You could just use multiple text blocks
<local:ExtendedTreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubOrganLocations}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding OrganDisplayName}" />
<TextBlock Grid.Column="1" Text="{Binding TypeName}" />
</Grid>
</HierarchicalDataTemplate>
</local:ExtendedTreeView.ItemTemplate>
Or you could add a property to your view model which calculate the full name internally and just bind to that.
Or use <Run/>:
<TextBlock>
<Run Text="{Binding OrganDisplayName}"/>
<Run Text=" ("/>
<Run Text="{Binding TypeName}"/>
<Run Text=")"/>
</TextBlock>
Related
I have a strange behaviour using ObjectDataProvider. I need to bind a TextBlock with ToString method but, when I enter in method my properties are wrong.
This is my simple ObjectDataProvider:
<Window.Resources>
<ObjectDataProvider x:Key="ToString" MethodName="ToString" ObjectType="{x:Type entities:Season}" />
</Window.Resources>
And this is my ListView:
<ListView Grid.Row="2" Name="lvSeasons" HorizontalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Source={StaticResource ToString}}" VerticalAlignment="Center" />
<Button Grid.Column="1" VerticalAlignment="Center" Background="Transparent" BorderBrush="Transparent" Click="btDeleteSeason_Click">
<TextBlock FontFamily="{StaticResource FontAwesome}" Text="" FontSize="20" Foreground="Red" HorizontalAlignment="Center" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My method simply concat two properties:
public override string ToString()
{
return StartYear + "/" + EndYear;
}
In debug I can see that start and end year are always 0. If I bind my TextBlock using {Binding StartYear} it's correct and value is 2019.
Where can the problem be?
You do not need an ObjectDataProvider. Just write
<TextBlock Text="{Binding}" ... />
WPF will call the ToString method by default.
You do not even need to override ToString when you use a MultiBinding with an appropriate StringFormat:
<TextBlock ...>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}/{1}">
<Binding Path="StartYear "/>
<Binding Path="EndYear "/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
I have this StackPanel in one grid on my form:
<StackPanel x:Name="panelWeelyBibleReading" Grid.Row="2" Grid.Column="0" Margin="2">
<Label>Bible Reading for Week:</Label>
<TextBox x:Name="textWeeklyBibleReading">PSALMS 60-68</TextBox>
</StackPanel>
<StackPanel Grid.Row="3" Grid.Column="0" Margin="2">
<Label>Opening Song:</Label>
<ComboBox x:Name="comboSongOpen" ItemsSource="{StaticResource SongTitles}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="local:SongTitleItem">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Number, StringFormat='000 - '}" />
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.MaxWidth>
<Binding Path="ActualWidth"
ElementName="textWeeklyBibleReading"/>
</ComboBox.MaxWidth>
</ComboBox>
</StackPanel>
Further down the form in a different grid I have this :
<StackPanel Grid.Row="3" Grid.Column="0" Margin="2">
<Label>Closing Song:</Label>
<ComboBox x:Name="comboSongEnd" ItemsSource="{StaticResource SongTitles}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="local:SongTitleItem">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Number, StringFormat='000 - '}" />
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.MaxWidth>
<Binding Path="ActualWidth"
ElementName="panelWeeklyBibleReading.textWeeklyBibleReading"/>
</ComboBox.MaxWidth>
</ComboBox>
</StackPanel>
Initially I tried using the same "textWeeklyBibleReading" for the MaxWidth in the second combo. But it doesn't work. No warnings. Just doesn't work. So I thought about applying a name to the previous StackPanel in teh hopes I could use it as some kind of access point. But it still doesn't work.
So my problem is that I need to set the MaxWidth on the second combo, which is in a different grid, but using the value that was calculated on the first grid combo. Am I making sense?
I would show the complete form markup if it helps.
You should edit to:
<ComboBox.MaxWidth>
<Binding Path="Width"
ElementName="textWeeklyBibleReading"/>
</ComboBox.MaxWidth>
<Binding Path=Width, ElementName=textWeeklyBibleReading/>
cause there is no property such as ActualWidth, instead it should be Width. And there is no need to write container name panelWeeklyBibleReading, just write ElementName that you need.
Update:
<ComboBox.ItemTemplate>
<DataTemplate DataType="local:SongTitleItem">
<StackPanel Orientation="Horizontal" MaxWidth="{Binding Path=Width,
ElementName=textWeeklyBibleReading}">
<TextBlock Text="{Binding Number, StringFormat='000 - '}" />
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
You should set MaxWidth of StackPanel of ComboBox cause outer StackPanel``(<StackPanel Grid.Row="3" Grid.Column="0" Margin="2">) which contains your ComboBox automatically sets Width to the outer StackPanel to your ComboBox. So I suggest to bind Width of your ComboBox to its ItemTemplate. Cause ItemTemplate has Data/template, then it is better to bind Width of ComboBox to StackPanel located into your DataTemplate.
How could I achieve this behavior in my ComboBox items: (n): Name
Where n and Name are two bindable properties. Right now I have n Name
This is my code:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding n}" />
<Run Text="{Binding Name}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
I think that adding two <Run Text="("/>, etc it can be done but there must be something more elegant in XAML.
Ok it was easy:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}({0}): - {1}">
<Binding Path="n" />
<Binding Path="Name" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
Another way is using multiple TextBlocks like so:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=...}"></TextBlock>
<TextBlock Text="{Binding Path=...}"></TextBlock>
</StackPanel>
</DataTemplate>
You can replace the StackPanel with a WrapPanel or whatever you like.
I want to show in one combobox content from two database columns. I would like to show "Name Surname" but I don't know how. I'm working in C# (.NET) using MVVM pattern. "Name" and "Surname" are fields from table "tblGuests".
Thanks in advance,
Vladimir
You could create an ItemTemplate for the ComboBox that binds to all the properties you want to show.
<ComboBox ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}" Padding="10,0,0,0"/>
<TextBlock Text="{Binding Path=LastName}" Padding="10,0,0,0"/>
</StackPanel>
<DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You could even create a UserControl that can be re-used and use that:
<PersonView>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}" Padding="10,0,0,0"/>
<TextBlock Text="{Binding Path=LastName}" Padding="10,0,0,0"/>
</StackPanel>
</PersonView>
<ComboBox ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<PersonView/>
<DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Keep a string list property in Viewmodel,
populate that property in a data loading method, by combining name and surname strings,
bind string property to combo box,
<ComboBox Name="ComboBox1" ItemsSource="{Binding YourStringListProperty}"/>
Another option could be to use MultiBinding something like this
<TextBlock Name="textBox2" DataContext="{StaticResource NameListData}">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource myNameConverter}"
ConverterParameter="FormatLastFirst">
<Binding Path="FirstName"/>
<Binding Path="LastName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
This code was taken directly from msdn. Refer to it for more details
I need load some data(Employee) in a listbox with check box. So the problem is how can I load other values, because in this moment only I can load the "Name" of the employee, and I need load other datas like "LastName", "Age", ...etc
I don't know how should be the syntax in the Content.
This is the xaml
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="CheckBoxZone" Content="{Binding Name}" Tag="{Binding TheValue}" Checked="CheckBoxZone_Checked"
Margin="0,5,0,0"/>
</DataTemplate>
</ListBox.ItemTemplate>
Basically you have to enhance layout of the ListItem template so along with CheckBox you can display another controls:
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Name="CheckBoxZone" Content="{Binding Name}" Tag="{Binding TheValue}" Checked="CheckBoxZone_Checked" Margin="0,5,0,0"/>
<TextBlock Grid.Column="1" Text="{Binding LastName}"></TextBlock>
</Grid>
</DataTemplate>
If you want to pass item itself to a content of CheckBox (why you need that?) use simply this:
<CheckBox Grid.Column="0" Name="CheckBoxZone" Content="{Binding}" Tag="{Binding TheValue}" Checked="CheckBoxZone_Checked" Margin="0,5,0,0"/>
For most flexibility, use a DataTemplate for the CheckBox.
<CheckBox Content="{Binding }">
<CheckBox.ContentTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Name}"/>
<Run Text="{Binding Family}" FontWeight="Bold"/>
<Run Text="{Binding Age, StringFormat='({0:d})'}" FontStyle="Italic"/>
</TextBlock>
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
[Assuming Age is of type int, use {0:f} if it's a double]
This will result in something like this: Maikol Smith (36)
Each Run tag should be on a new line for the TextBlock to insert a space between them.