combining two field into one Text content wpf - wpf

I want to combine Name and ID of the song in the header of Song. Would it be possible if I have:
Song
{
public string Name {get; set;}
public int ID {get; set;}
}
I want to bind them into the Header of an Expander. At the moment, for binding with only one property. it is like this:
<Expander Foreground="#FFF4E7CA" Header="{Binding Song.Name}" FontWeight="Bold">
</Expander>
But I want to be some thing like this:
Header = "{Binding Some.Name, Song.ID}"
Is it possible somehow then? and if yes, how? THanks in advance.

Something like this:
<Expander ...>
<Expander.Header>
<TextBlock>
<TextBlock Text="{Binding Song.Name}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Sond.ID}"/>
</TextBlock>
</Expander.Header>
...
</Expander>

You could either
1) expose a new property on your view model and bind to that
Song
{
public string Name {get; set;}
public int ID {get; set;}
public string Header {get { return string.Format("{0} {1}", Name, ID); } }
}
2) use a multi-binding with a string format
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="Song.Name"/>
<Binding Path="Song.Id"/>
</MultiBinding>
</TextBlock.Text>
3) If you're using WPF4, then Run is bindable so the answer regarding using Run would then work.

Yes you can use the multibinding class

Related

MultiValueConverter reading from ObservablleCollection

I am working on a wpf mvvm project. In a user control I have a datagridControl from Devexpress that is bound to data from a Observable collection.
<xcdg:DataGridControl x:Name="DataGridName" HorizontalAlignment="left" VerticalAlignment="Stretch"
AutoCreateColumns="False"
ItemsSource="{Binding ViewModel.Items}"
ItemScrollingBehavior="Immediate" SynchronizeCurrent="True" TabIndex="69" >
<xcdg:DataGridControl.Columns >
<xcdg:Column FieldName="Name" AllowSort="False" Title="Name" ShowInColumnChooser="False" />
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
The class in the Observable collection Contains a Name (string) and IsVerified (Boolean).
private ObservableCollection<myData> _items = new ObservableCollection<myData>();
public ObservableCollection<myData> Items
{
get { return _items; }
set { _items = value; }
}
public class myData
{
public string Name { get; set; }
public bool IsVerfied { get; set; }
}
I also have a textblock that I use to display an error message above the dataGrid when the Value of IsVerfied is false.
<TextBlock Name="textBlockErrrMessage" Foreground="IndianRed">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding Path="DataContext.IsVerified" RelativeSource="{RelativeSource AncestorType=xcdg:DataRow}" ElementName="DataGridName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
To do this I plan on having a multivalueconverter (I am also doing the same thing but for a different control so that is why I choose a MultiValueConverter) that I would like to send the IsVerfied value from the Collection and return the message. My issue is how do I set the Binding in the MultiBinding to read the IsVerfied value from the Observablecollection. This particular line is what I believe is the issue in locating the Collection value
<Binding
Path="DataContext.IsVerified"
RelativeSource="{RelativeSource AncestorType=xcdg:DataRow}"
ElementName="DataGridName" />
In your Binding, you want to use either RelativeSource or ElementName, but not both. See this post for a good clarification on the differences between the two.

Binding as a Resource

Can I define a Binding as a Resource and then reuse it with different Controls properties?
Example:
Binding:
<Window.Resources>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</Window.Resources>
Reuse in XAML:
<TextBox Text="{StaticResource MyBinding}" />
After declaring Binding as above I got the error:
"The name 'InitializeComponent' does not exist in the current
context"
Is there any way to reuse the same Binding in different contexts?
Direct answer to your question is "yes, you can define a binding as a resource". The problem here is how do you then make any use of it? One possibility is to create an extension class which would pull the binding from the resources and apply it:
public class BindingResourceExtension : StaticResourceExtension
{
public BindingResourceExtension() : base() { }
public BindingResourceExtension(object resourceKey) : base(resourceKey) { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = base.ProvideValue(serviceProvider) as BindingBase;
if (binding != null)
return binding.ProvideValue(serviceProvider);
else
return null; //or throw an exception
}
}
Usage example:
<Window.Resources>
<ResourceDictionary>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</ResourceDictionary>
</Window.Resources>
(...)
<TextBox Text="{ns:BindingResource MyBinding}" />
Can this solution be used in MultiBinding?
Yes, it can:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<ns:BindingResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
There is however one drawback to this - although everything will work in run-time, the XAML Designer will complain that BindingResourceExtension is not of proper type to be put in the MultiBinding.Bindings collection. But, thankfully, there is a quick solution - simply use StaticResourceExtension instead! So this, while being functionally equivalent in run-time, will be accepted by the designer:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<StaticResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Here are two ways to not do exactly what you want:
1. Using a custom markup extension
Skipped all nullchecks etc. to keep it short.
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public class BindingDefinition
{
public PropertyPath Path { get; set; }
public BindingMode Mode { get; set; }
}
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class ApplyBindingDefinition : MarkupExtension
{
public BindingDefinition Definition { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Path = this.Definition.Path,
Mode = this.Definition.Mode
};
return binding.ProvideValue(serviceProvider);
}
}
<Window.Resources>
<local:BindingDefinition x:Key="MyProperty"
Mode="TwoWay"
Path="MyProperty" />
</Window.Resources>
<TextBox>
<TextBox.Text>
<!-- using element style here as the parser chokes on parsing nested markupextensions -->
<local:ApplyBindingDefinition Definition="{StaticResource MyProperty}" />
</TextBox.Text>
</TextBox>
2. Making the PropertyPath a resource
May or may not be enough for your needs.
<Window.Resources>
<PropertyPath x:Key="MyPropertyPath">MyProperty</PropertyPath>
</Window.Resources>
...
<TextBox Text="{Binding Path={StaticResource MyPropertyPath}}" />

Treeview binding problem

I have a window MainWindow.xaml and
private static Tutorial tutorial; there.
Also I have class Structure.cs where I describe child types
public class Tutorial
{
public string Name { get; set; }
public IList<Chapter> Chapters = new List<Chapter>();
}
public class Chapter
{
public string Name { get; set; }
public IList<Unit> Units = new List<Unit>();
}
public class Unit
{
public string Name { get; set; }
public IList<Frame> Frames = new List<Frame>();
...
}
I want to bind tutorial structure to treeview. How can I do this?
I tried this way.
<TreeView Grid.Row="2" x:Name="treeViewStruct" Margin="5,0,5,0" Background="LemonChiffon" BorderBrush="Bisque" BorderThickness="1" ScrollViewer.VerticalScrollBarVisibility="Auto" IsTextSearchEnabled="True" Cursor="Hand">
<TreeView.Resources>
<HierarchicalDataTemplate DataType = "{x:Type Structure:Chapter}"
ItemsSource = "{Binding Path=Units}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type Structure:Unit}">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
It doesn't work.
Please, help! I'm a newbie in WPF. I need dynamic tree
so that when I add a chapter or a unit in the object tutorial, tree is updated.
And for this way of binding please throw the idea how can I get a collection item, when I selected some tree node.
This may help :
<HierarchicalDateTemplate DataType = "{x:Type local:Tutorial}"
ItemsSource="{Binding Chapters}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDateTemplate>
<HierarchicalDateTemplate DataType = "{x:Type local:Chapter}"
ItemsSource="{Binding Units}"
<TextBlock Text="{Binding Name}"/>
</HierarchicalDateTemplate>
<DateTemplate DataType = "{x:Type local:Unit}"
<TextBlock Text="{Binding Name}"/>
</DateTemplate>

Does StringFormat work with this.DataContext

I am binding a TextBlock with a collection in code-behind via this.DataContext = SellerList;
The output is correct but when i apply StringFormat, i see no result. Following is the code for TextBlock on xaml page
<TextBlock Name="dateDTKey" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Text="{Binding Path=Date, StringFormat={}{0:dd-MM-yyyy}}"
Style="{StaticResource textStyleTextBlock}"/>
The source for the Binding is a string, if detailsSellerListingTemplate is a resource you should use {StaticResource detailsSellerListingTemplate}. Also, the TextBlock doesn't need a DataContext for this Binding to work since it's using Source.
<Window.Resources>
<local:DetailsSeller x:Key="detailsSellerListingTemplate"/>
</Window.Resources>
<TextBlock Name="dateDTKey"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Text="{Binding Source={StaticResource detailsSellerListingTemplate},
Path=Date,
StringFormat={}{0:dd-MM-yyyy}}"/>
This will work if DetailsSeller looks similar to this
public class DetailsSeller
{
public DetailsSeller()
{
Date = DateTime.Now;
}
public DateTime Date
{
get;
set;
}
}
You talked about a collection but I can't see how that fits with the binding, so maybe I missunderstood something in the question
I am thinking its because you have way to many braces in your string format. try this:
StringFormat={0:dd-MM-yyyy}

Tricky WPF binding

I'm unable to do a simple but yet tricky WPF binding in Silverlight 4 (WP7 development)
I have the following code:
Class People{
public string firstname;
public string lastname;
}
Class DataSource{
public static List<People> people; // consider this as a list filled with objects already
}
I'm trying to put the list of people into a ListBox, here's the xaml I've tried:
<ListBox x:Name="peoplelistbox" Margin="0,0,-12,0" ItemsSource="{Binding DataSource.people}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding firstname}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding lastname}" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But unfortunately my listbox remains empty. What am I doing wrong ?
Thank you in advance :)
Cheers,
Miloud B.
Firstly you are using fields, where you should use public property (i.e. people, firstname and lastname). Convert people to a public property, like this:
public static List<People> people { get; set; }
Then, you need to bind the ItemsSource using x:Static markup, like this:
<ListBox x:Name="peoplelistbox" Margin="0,0,-12,0">
<ListBox.ItemsSource>
<Binding Source="{x:Static local:DataSource.people}"/>
<ListBox.ItemsSource/>
...
PS: local is the xml namespace pointing to your DataSource class's namespace. Also, your class too needs to be a public class.
EDIT:
For WP7, you need to declare the instance of the class in the resources and then you can use Path to point to the source. Like this:
<phone:PhoneApplicationPage.Resources>
<local:DataSource x:Key="dataSource"/>
</phone:PhoneApplicationPage.Resources>
...
<ListBox x:Name="peoplelistbox" Margin="0,0,-12,0" ItemsSource="{Binding Source={StaticResource dataSource}, Path=people}">
PS: Again, your class needs to be public and must have a default constructor.
EDIT:
Here is a example which is working perfectly on my system. Check and see where are you making the mistake:
namespace WindowsPhoneApplication1
{
public class People
{
public string firstname { get; set; }
public string lastname { get; set; }
}
public class DataSource
{
public static List<People> people { get; set; }
public DataSource() { }
static DataSource()
{
people = new List<People> {new People {firstname = "Foo", lastname = "Bar"}};
}
}
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
}
}
Xaml (only the relevant portions):
...
...
xmlns:local="clr-namespace:WindowsPhoneApplication1"
...
...
<phone:PhoneApplicationPage.Resources>
<local:DataSource x:Key="dataSource"/>
</phone:PhoneApplicationPage.Resources>
...
...
<ListBox x:Name="peoplelistbox" Margin="0,0,-12,0" ItemsSource="{Binding Source={StaticResource dataSource}, Path=people}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding firstname}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding lastname}" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
1.FirstName and LastName need to be public properties with at least getters.
2.Your list should also be a public property unless you explicitly set the DataContext of your Window
3.Need to either set the DataContext or reference the source otherwise.
4.You cannot bind to static properties like that, use {x:Static ...}.
5.This is not a tricky binding -.-
As devdigital said you might want to implement those interfaces as well.
You can only bind to properties, so change your public fields to properties.
Also, if you want your UI to update on programmatic changes to your people instances, then implement INotifyPropertyChanged on your People type (really that type should be called Person).
If you want your UI to update when items are added/removed from your DataSource people collection, then use ObservableCollection<T> rather than List<T>.

Resources