Bind Images in ComboBox using DataTemplate - wpf

I am working on an existing code. This thing has got a ComboBox with a few ComboBoxItems. Each items has got a StackPanel withing which there is an Image control and a TextBlock.
Now the source property of the Image control is set to different vector images stored in XAML files whereas the Text property of the TextBlock is set to a localized string.
I want to implement this not by having separate ComboBoxItems but by using DataTemplate. I can create a List of the strings for the TextBlock but I am not able to figure out as to how can I bind the images to the respective Image Controls.
I am open to any other better possible solution. Also, if you think that the right way to do it is the existing one, please let me know.
This might be a duplicate question but I couldn't find one that caters to my issue.
If it is, a link to the other question would suffice.
EDIT: Code Added
<ComboBox x:Name="imageInfoLevelsComboBox" SelectedIndex="1"
Style="{DynamicResource ComboBoxToolBarStyle}"
Margin="6,6,6,0" Width="50"
ToolTip="{x:Static Viewing:ViewingTexts.ImageInformationLevels}"
SelectionChanged="OnImageInfoLevelsComboBoxSelectionChanged" >
<ComboBoxItem x:Name="showAllComboBoxItem"
Style="{DynamicResource ComboBoxItemToolBarStyle}">
<StackPanel Orientation="Horizontal">
<Image x:Name="ImageInfoAllImage"
Source="{StaticResource ImageInfoFullIcon}"
Margin="0,0,4,0"
Width="24" Height="24"/>
<TextBlock
Text="{x:Static Viewing:ViewingTexts.ImageInformationFull}"
Margin="10,0,0,0"
VerticalAlignment="Center"/>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem x:Name="showImportantComboBoxItem"
Style="{DynamicResource ComboBoxItemToolBarStyle}">
<StackPanel Orientation="Horizontal">
<Image x:Name="ImageInfoImportantImage"
Source="{StaticResource ImageInfoLimitedIcon}"
Margin="0,0,4,0"
Width="24" Height="24"/>
<TextBlock
Text="{x:Static Viewing:ViewingTexts.ImageInformationIntermediate}"
Margin="10,0,0,0"
VerticalAlignment="Center"/>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem x:Name="showNotificationsComboBoxItem"
Style="{DynamicResource ComboBoxItemToolBarStyle}">
<StackPanel Orientation="Horizontal">
<Image x:Name="ImageInfoNotificationsImage"
Source="{StaticResource ImageInfoNoneIcon}"
Margin="0,0,4,0" Width="24" Height="24"/>
<TextBlock Text="{x:Static Viewing:ViewingTexts.ImageInformationNone}"
Margin="10,0,0,0" VerticalAlignment="Center"/>
</StackPanel>
</ComboBoxItem>
</ComboBox>
What I think I can do is create a class with 2 objects, one of type string and the other as Image. And then create a list and bind it with the combobox, but the issue is that I am nto sure how to use the vector image as an object.
Thanks.

I think you need to bind a list of objects with at least two properties instead of just a list of strings. One property would contain the string for the text block, the other property would be a urisource for the image.
Refer to this link for examples of urisource definitions Wpf - relative image source path

Bind the ItemsSource of your ComboBox to a collection of objects that has properties representing the text and the image. Then you need to create a IValueConverter and specify an instance of it on the binding of your image that can convert the value of the property on your object to a image source.
Here is one example:
http://www.codewrecks.com/blog/index.php/2010/07/23/bind-an-image-to-a-property-in-wpf/

Related

Binding a ComboBox selection to the background color of a border.

Please forgive my ignorance. I am new to vb.net and WPF. I have a comboBox that has a list of colors like this. By the way this is in WPF.
Public Sub New()
InitializeComponent()
cmbColors.ItemsSource = GetType(Colors).GetProperties()
End Sub
In the XAML the comboBox is created as follows:
<ComboBox Name="cmbColors" HorizontalAlignment="Left" Margin="29,35,0,0"
Grid.Row="1" VerticalAlignment="Top" Width="120">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}" Width="16" Height="16"
Margin="0,2,5,2"/>
<TextBlock x:Name="cmbColorsText" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
What I'm trying to do is when the program is run start with a beginning background color of grey, and when a new background color is selected from the comboBox the back ground will update.
Here's the XAML of the element that I'm trying to bind to the selection.
<Border BorderBrush="{x:Null}" Grid.Column="1" Grid.Row="1" Background="{Binding Text, ElementName=cmbColors}">
<TextBlock Text="PRACTICE" Style="{StaticResource linkButtons}"/>
I have gone through every (string) type in the property window for the border>background>create binding>Element>comboBox and for some reason (that I can't determine) I have either missed the appropriate one or am looking at this the wrong way.
Thank you in advance!!!
You are binding the Background to a string, but the Background will need a ColorBrush. So, if your combo ItemsSource already contains items that are of ColorBrush then you can just bind to SelectedItem rather than Text.
Or you can use a converter in your Background binding, that takes the string and returns a SolidColorBrush, say.
Change the binding to
<Border BorderBrush="{x:Null}" Grid.Column="1" Grid.Row="1" Background="{Binding SelectedItem.Name, ElementName=cmbColors}">
<TextBlock Text="PRACTICE" Style="{StaticResource linkButtons}"/>
The Text property of the ComboBox is returning the result of the ToString() method of the PropertyInfo object, so for instance if you select Black, it will be "System.Windows.Media.Color Black" and won't be parsed as a valid color.

How to change HirerachicalDataTemplate associated with the WPF TreeView programatically at run time?

I have a TreeView control on my WPF window. I am giving only relevant XAML from my window.
<Window.Resources>
<HierarchicalDataTemplate x:Key="HierarchicalTemplate" ItemsSource="{Binding SubOrgUnitItems}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="{Binding ImagePath}" Stretch="Fill" Width="16"/>
<TextBlock Text="{Binding OrgUnitName}" Name="treeText" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView Margin="10,35,10,10" BorderThickness="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsTabStop="True" Name="orgTreeView" ItemsSource="{Binding}" ItemTemplate="{DynamicResource HierarchicalTemplate}" TabIndex="700" SelectedItemChanged="orgTreeView_SelectedItemChanged" />
When the Collection of Organisations is bound to DataContext of the TreeView, items are displayed with the OrgUnitName's value as a text at every node.
Now at run time I want to see some other property's value as a text at every node. e.g. OrgUnitCode instead of OrgUnitName. Both are properties declared in the view model class associated with the treeview.
How can i do it programatically at run time?
You should use HierarchicalDataTemplateSelector.
Define two different HierarchicalDataTemplate (as you did).
Inherite your custom selector class from DataTemplateSelector, override its SelectTemplate method and put there the logic of the selection. This method will return the correct template in each case.
Create a Resource(Custom Selector class) in the xaml file.
Set the TreeViews ItemTemplateSelector to the static selector resource.
See a simple example here: Link
I have achieved what I wanted to do, but unfortunately by some work around. Following thing worked for me but it may not be the correct answer to the problem.
I added one more HirerachicalDataTemplate and TreeView. The new template uses the OrgUnitCode property. The new tree view uses the new template.
<HierarchicalDataTemplate x:Key="HierarchicalTemplateUsingCode" ItemsSource="{Binding SubOrgUnitItems}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="{Binding ImagePath}" Stretch="Fill" Width="16"/>
<TextBlock Text="{Binding OrgUnitCode}" Name="treeText" />
</StackPanel>
</HierarchicalDataTemplate>
<TreeView Margin="10,35,10,10" BorderThickness="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsTabStop="True" Name="orgTreeViewCode" ItemsSource="{Binding}" ItemTemplate="{DynamicResource HierarchicalTemplateUsingCode}" TabIndex="700" SelectedItemChanged="orgTreeViewCode_SelectedItemChanged" Visibility="Hidden"/>
At run time, when I want to see OrgUnitCode property value as a text at the node, I simply make new tree visible and hide the first one (mentioned in question). So making tree views visible/invisible help me to achieve what I wanted to do.

Image from object in Datagrid template column

I am trying to display an image in my datagrid in a template column, the code:
<data:DataGridTemplateColumn Header="" x:Name="colPriority">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderBrush="Black" Background="{Binding TimeMarker.TimeMarkerBrush}" BorderThickness="1" Width="38" ToolTipService.ToolTip="{Binding Path=TimeMarker.TimeMarkerName, StringFormat='Priority: {0}'}">
<Image
Source="{Binding ImageFlag}"
ToolTipService.ToolTip="{Binding TaskFlagStatus}"
Height="32"
Width="32"
Margin="3"/>
</Border>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
'ImageFlag' is a property of type 'image' in my object. The problem is that it is not showing up. When I change the source in the xaml to the relative URI of an image it shows up fine, but it won't show the image that is stored in the 'ImageFlag' property of my object. Why?
The object type you should be exposing in your model should be one that derives from ImageSource such as BitmapImage.
The Image class is the element that displays an ImageSource, you can't assign an instance of Image to the Source property of another Image.

WPF Element Binding in a within a Resource control doesnt work

I have some xaml that will just copy text from one text box to another:
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src1, Path=Text}" />
<TextBox x:Name="src1" Width="100" Height="30" />
</StackPanel>
Nothing special, works fine. A bit dumb but just an example.
However if I put the StackPanel as a resource in the Window and create dynamically from code, like this:
<Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
</Window.Resources>
.. then the element binding doesnt work anymore.
Why? and how to make it work? Any ideas gratefully received.
The following Xaml should work just fine
<Window ...>
<Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
</Window.Resources>
<StaticResource ResourceKey="MySP"/>
</Window>
You could also use it from code
StackPanel mySP = TryFindResource("MySP") as StackPanel;
if (mySP != null)
{
this.Content = mySP;
}
However, what is the reason for you to have a StackPanel in the Windows Resoures?
If you want to be able to reuse it several times you would have to set x:Shared="False" on the Resource but then you'll get an exception saying something like Cannot register duplicate Name 'src' in this scope the second time you add it.
As far as I'm concerned you should not put that in <Window.Resources>. Only styles, static, dynamic resources and such...
http://msdn.microsoft.com/en-us/library/ms750613.aspx
<Window>
<Window.Resources>
</Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
<Window>
Having a similar issue, trying to get relative binding to my source control - In my case, I'm creating a designer and need the element as a static so styles can use it's dimensions for centering calculations on a canvas.
Taking a line from [WPF Xaml Namescopes],
ResourceDictionary does not use XAML names or namescopes ; it uses keys instead, because it is a dictionary implementation.
So, directly using ElementName in a resource Dictionary simply does not work, because no name will bind without a NameScope. Also attempted reproducing your situation with Style setters, but no luck - one cannot set an object's name via a Style.
Now, the convoluted solution I cam up with is to
Create a DependencyProperty in the code-behind of the class
you're declaring this resource in.
replace ElementName=Root with RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type namespace:RootClass}} and bind
to said container directly, allowing you to bind to said
DependencyProperty whilst bypassing the names.
If you need bindings to operate between two elements in the same
StaticResource, bind the source to said DependencyProperty as
OneWayToSource or TwoWay, and the destination as OneWay or TwoWay.
1

Pattern for working with a form in Silverlight 4? (How to get references to XAML elements)

I have a form:
<StackPanel Orientation="Horizontal" Visibility="{Binding Editable, Converter={StaticResource visibilityConverter}}"
ToolTipService.ToolTip="Add new topic to this group">
<sdk:AutoCompleteBox Width="160" ItemsSource="{Binding ElementName=LayoutRoot, Path=DataContext.TopicNames}" />
<Button Click="addTopicButton_Click">
<Image Source="Images/appbar.add.rest.png" />
</Button>
</StackPanel>
This form appears in a DataTemplate for an ItemsControl. I'm not sure what the best way is to get the data from the AutoCompleteBox when the button is clicked. I can't give the elements x:Name attributes, because they're in a template (right?).
How can I get around this? The Click event will give me the Button, but I need a reference to the text box. Use the Button's parent, then look through the children for the Textbox? If I factored this out into its own UserControl, I could set x:Name values, but I'd rather not do that.
Any other ideas?
Update: Here is another example of such a problem:
<ListBox x:Name="topicList"
ItemsSource="{Binding Id, Converter={StaticResource topicGroupIDConverter}}"
SelectionChanged="ListBox_SelectionChanged"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Width="150"
VerticalAlignment="Center"
ToolTipService.ToolTip="{Binding Description}"
ToolTipService.Placement="Right" />
<Button ToolTipService.ToolTip="Remove this topic from this group"
Visibility="{Binding ElementName=topicList,
Path=DataContext.Editable,
Converter={StaticResource visibilityConverter}}"
Click="removeTopicButton_Click"
HorizontalAlignment="Right"
Margin="10,0">
<Image Source="Images/appbar.cancel.rest.png" />
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When the button is clicked, I want to access topicList.DataContext. However, topicList itself is a DataTemplate in an ItemsControl, so I can't access it using its name from code-behind. How else can I do this?
You can add a property, say SelectedItemInAutoCompleteBox, to your presenter, and then can bind it to the SelectedItem property of AutoCompleteBox, using Mode=TwoWay, like this,
<sdk:AutoCompleteBox SelectedItem="{Binding Path=DataContext.SelectedItemInAutoCompleteBox, Mode=TwoWay}" ... />
You may try the same approach with Text property of AutoCompleteBox, also. See if it solves your problem.:-)
You have several choices:
If you're on Silverlight 5, use the AncestorBinding
Otherwise, use a Silverlight 4 AncestorBinding hack (it doesn't look pretty)
Or you could try DataContextProxy, which stores the DataContext in a resource so that it is accessible. Note: you should set the DataContextProxy as a Resource of topicList ListBox, not the UserControl as in Dan Wahlin's example.

Resources