Binding multiple Sources to a ListView - wpf

I have a ListView with a dataTemplate which I need to bind to 3 different sources with the same index. I think I have to do this completely in XAML, because the sources (chart) only exists in xaml. I'm using the MVVM Pattern."
I have wrote down how it "should" work, the index i is the common key.
<ListView ItemsSource="{Binding ???}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- Small rectangle filled with the same color as the corresponding line -->
<Rectangle
Height="10"
Width="10"
Fill="{Binding ElementName=chart, Path=Series[i].LineStroke}" />
<!-- The title of the corresponding line -->
<TextBlock
x:Name="Title"
Text="{Binding ElementName=chart, Path=Series[i].DataSeries.Title}" />
<!-- The actual value of the corresponding line on the current position-->
<TextBlock
x:Name="Value"
Text="{Binding ElementName=chart, Path=Behaviour.Behaviours[0].CurrentPoints[i].Y}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Mh, lets see. How about you bind you listview to chart.Series this way you get the right number of elements. An then in your data template you bind the properties of the series. For the behaviour you could use MultiBinding and a converter to extract the data
<ListView ItemsSource="{Binding Path=Series, ElementName=chart}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- Small rectangle filled with the same color as the corresponding line -->
<Rectangle
Height="10"
Width="10"
Fill="{Binding Path=LineStroke}" />
<!-- The title of the corresponding line -->
<TextBlock
x:Name="Title"
Text="{Binding Path=DataSeries.Title}" />
<!-- The actual value of the corresponding line on the current position-->
<TextBlock x:Name="Value">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ChartSeriesBehaviourConverter}">
<Binding ElementName=chart/>
<Binding/>
<MultiBinding>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now you should get the chart and the current series object passed into your converter where you should be able to do something like var idx = chart.Series.IndexOf(s) so you can access the corresponding point in the behaviours.

Related

How can I make a control in Wpf depend on a property in viewmodel?

I have this codes, but I don't want just make control visible or invisible , I don't want to create it, because it works in background and does some work that takes time and I don't want it. how can I do that? Can I use if condition in xaml in wpf? I've heard about triggers but I don't know how to do that in my example?
<ContentControl Content="{Binding ViewService[NoteSaveView]}" Visibility="{Binding ViewModeVisibility[Insert]}"/>
<telerik:RadTabControl TabOrientation="Horizontal" TabStripPlacement="Right" Padding="5" BorderThickness="0" Margin="0 -5 -5 -5" Visibility="{Binding ViewMode,Converter={StaticResource UpdateViewToVisibility}}">
<telerik:RadTabItem Header="صفحه اصلی" Content="{Binding ViewService[NoteSaveView]}"/>
<telerik:RadTabItem Header="تاریخچه" Content="{Binding ViewService[LogView]}"/>
</telerik:RadTabControl>
Edit:
finally I solved my problem with this code:
<ContentControl>
<ContentControl.Content>
<MultiBinding Converter="{StaticResource ViewModeVisibilityToContent}">
<Binding Path="ViewModeVisibility[Insert]"/>
<Binding Path="ViewService[NoteSaveView]"/>
</MultiBinding>
</ContentControl.Content>
</ContentControl>
You could use a DataType property of a DataTemplate and then assign a data object to the property to activate a DataTemplate or null to deactivate it.
In the code below you just need to set PropertyInViewModel of type object in viewmodel to some int to activate the DataTemplate, or to null to deactivate it.
<StackPanel xmlns:System="clr-namespace:System;assembly=mscorlib">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type System:Int32}">
<TextBox Text="{Binding Mode=OneWay}" Foreground="Beige" Background="Brown" Height="20" Width="50"/>
</DataTemplate>
</StackPanel.Resources>
<ContentControl Content="{Binding PropertyInViewModel}"/>
</StackPanel>

Define ComboBox' DataTemplate for TextBox (and define search pattern) when IsEditable is True?

I have a ComboBox whose ItemsSource is binding to a collection and the SelectedItem is binding to the properties of my VieModel. Let's call the binding properties AvailableOptions and TargetOption in ViewModel. And type of collection item and TargetOption is called MyOption. I have such requirements but I don't know how to fulfill them all:
It should be OK for the binding TargetOption to have NULL as value
I want to set a DataTemplate for the target type in TargetOption collection to be displayed in the ComboBox
If possible, I want use different DataTemplate for MyOption when then are in the drop-down of ComboBox and when one item is selected. Because my UserControl has limited space so it should be compact when item is selected and during the selection it should provide more information
As I said, I don't know how to do all of them. At first I have the XAML like this:
<ComboBox SelectedItem="{Binding SelectedOption} ItemsSource="{Binding AvailableOptions}" >
<ComboBox.ItemTemplateSelector>
<MyNameSpace:ComboBoxItemTemplateSelector ItemTemplate="{StaticResource OptionDetailTemplate}" SelectedItemTemplate="{StaticResource OptionSimpleTemplate}" />
</ComboBox.ItemTemplateSelector>
</ComboBox>
With a customized ItemTemplateSelector. I am able to do the requirement 2) and 3). My OptionDetailTemplate looks like this:
<DataTemplate x:Key="OptionDetailTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ShortName}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Code}" />
</StackPanel>
</DataTemplate>
and OptionSimpleTemplate looks like this:
<DataTemplate x:Key="OptionSimpleTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ShortName}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Code}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Number}" />
</StackPanel>
</DataTemplate>
But now the problem is requirement 1). When the user select one option from the drop down list of the ComboBox, he can't put it as NULL back which should be allowed. This is because AvailableOption doesn't have a NULL object
I see that if I set IsEditable to True for the ComboBox, and set TextSearch.TextPath to Code, it allows the text quick search/assign and also allows to have a NULL value when the search text is totally deleted. But now when I ever select one, it only displays Code (the OptionTemplate does not have any effect any more because now it displays the selected item in a TextBox). This is not good since only Code is not enough for the user to tell what Option it is. But since I have multiple properties in MyOption class, how can I define the DataTemplate for the TextBox and also define the search routine?
I have to be honest that I didn't fully understand your first requirement and its ramifications. however, I am really just answering to let you know that you don't even need to use a DataTemplateSelector to select between your two DataTemplates. If you do not set the x:Key value on them, then they will be applied to the relevant items implicitly:
<DataTemplate DataType="{x:Type YourXamlNamespacePrefix:TargetOption}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ShortName}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Code}" />
</StackPanel>
</DataTemplate>
...
<DataTemplate DataType="{x:Type YourXamlNamespacePrefix:MyOption}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ShortName}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Code}" />
<TextBlock Text=" | " />
<TextBlock Text="{Binding Number}" />
</StackPanel>
</DataTemplate>
Furthermore, you could do all this data binding with just a single TextBlock if you use a MultiDataTrigger:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}|{1}">
<Binding Path="ShortName" />
<Binding Path="Code" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Perhaps if you try clarifying your remaining problem (in your question), I might understand?

How to display too long text properly in WPF ComboBox

I have a ComboBox that shows text of various lengths. For texts that are not long there is not a problem. For the texts longer than the width of ComboBox I would like to trim the text and add "..." (an ellipsis) at the end to show them properly. The bottom line is that I don't want to change the width of the ComboBox. Does anyone know how to do this?
Use a custom ItemTemplate for your ComboBox, which makes use of a TextBlock with the TextTrimming property set to CharacterEllipsis.
Example:
<ComboBox ItemsSource="..." SelectedValuePath="...">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding ...}"
TextTrimming="CharacterEllipsis" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The answer, as Ross said, is to implement a custom ItemTemplate. However, to make it work properly, you need to do the binding properly.
A note on this method: You cannot set both the DisplayMemberPath and the ItemTemplate, it must be one or the other.
So, for the general case where the display member is the item (such as for a string), you can use binding with no properties to bind to the DataContext of the template:
<ComboBox ItemsSource="..." SelectedValuePath="...">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Or, you can put it in a style.
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding }" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
For the case where you want to bind to a specific property of the object, similar to how you would use the DisplayMemberPath property, replace the binding with the binding that you would use to a property on the object that you are binding. So, replace the fourth line in my first example with something like this:
<TextBlock Text="{Binding MyDisplayMemberProperty}" TextTrimming="CharacterEllipsis" />
The binding is in the context of a single item of the type bound to your ComboBox. To make this more explicit, you can do the following:
<DataTemplate DataType="{x:Type namespace:MyItemType}">
<!-- My DataTemplate stuff here -->
</DataTemplate>
This will give you hints for the properties on the object while you are writing code inside the DataTemplate.
You can use TextTrimming CharacterEllipsis or WordEllipsis for the textblocks in your combobox.
Also works with a more complex DataTemplate; however, I had to resort to a DockPanel instead of the standard WrapPanel.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<AccessText DockPanel.Dock="Left" Text="{Binding Icon}"/>
<TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis" />
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

WPF UserControl or ControlTemplate... (not sure)

I have a listbox where I have to add about 20 static custom items. All the items are based on the same template (something like that) :
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="" Height="30" />
<TextBlock Text="" VerticalAlignment="Center" />
</StackPanel>
</Border>
I don't want to repeat that 20 times in the ListBox.Items I would like to have some kind of UserControl where I could do something Like the following where I could set some custom properties :
<ListBox>
<ListBox.Items>
<MyListBoxTemplate x:Name="Item1" ItemText="Item #1" ItemImageSource="/Image1.jpg" />
<MyListBoxTemplate x:Name="Item2" ItemText="Item #2" ItemImageSource="/Image2.jpg" />
...
</ListBox.Items>
</ListBox>
But I don't wan't to create a userControl just for that!!! Is there an easy way to put that template in the Window.Resources?
Thanks
If you are ONLY using it for that SPECIFIC listbox, you can just assign the ItemTemplate property. This will need to work in conjunction with a collection of custom objects defined in your resources somewhere else. This will save you from creating a custom UserControl, but you will need an object that can be defined in XAML and a list of them in XAML anyway. To be honest, creating a UserControl is relatively painless and may be easier, but it is possible without doing so.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate TargetType="CustomObjectType">
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Height="30" />
<TextBlock Text="{Binding TextContent}" VerticalAlignment="Center" />
</StackPanel>
</Border>
<DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT: If you are going to use it in more than one place, put the DataTemplate in your Application resources and ive it a key, then assign the ItemTemplate property to {StaticResource MyListBoxItemsTemplateKey}
Not my favorite approach since it uses the XmlDataProvider and XPath syntax (which I tend to always forget). But you can embed your static data as xml within your Window.Resources like so:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="MyStaticData" XPath="StaticItems" >
<x:XData>
<StaticItems xmlns="">
<StaticItem>
<ItemText>Item #1</ItemText>
<ItemImageSource>/Image1.jpg</ItemImageSource>
</StaticItem>
<StaticItem>
<ItemText>Item #2</ItemText>
<ItemImageSource>/Image2.jpg</ItemImageSource>
</StaticItem>
</StaticItems>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox>
<ListBox.ItemsSource>
<Binding Source="{StaticResource MyStaticData}" XPath="StaticItem" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding XPath=ItemImageSource}" Height="30" />
<TextBlock Text="{Binding XPath=ItemText}" VerticalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Then within your ListBox bind to the XmlDataProvider you specified and use the XPath notation within the bindings to drill down to the data you want the controls to bind to.
This site has a couple good examples too:
http://vbcity.com/blogs/xtab/archive/2010/12/24/more-xpath-examples-in-a-wpf-application.aspx
Hope this helps!

How to create a standard DataTemplate for DataGridTemplateColumn?

I've got a DataTemplate for a DataGridTemplateColum wich looks like this:
<toolkit:DataGridTemplateColumn x:Name="DataGridTextColumnIstVorvorjahr" IsReadOnly="True" SortMemberPath="SummeIstVorvorjahr">
<toolkit:DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Background="Transparent" Margin="0,-5">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock Panel.ZIndex="100" Style="{DynamicResource CellText}" Text="{Binding Path=SummeIstVorvorjahrGerundet, Converter={StaticResource numberFormatter}, ConverterParameter='#,0.0 T€'}" DockPanel.Dock="Right"/>
<Image Panel.ZIndex="90" DockPanel.Dock="Left" MouseLeftButtonUp="FilterDataGridAnalyse_MouseDoubleClick" HorizontalAlignment="Left" Margin="5,0,0,0" Width="20" Height="20" Visibility="Hidden" Name="ImageNormal" Source="pack://application:,,,/Cis.Common.Presentation;component/Resources/Images/Lupe.png" />
</DockPanel>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ImageNormal" Property="Visibility" Value="Visible" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
<toolkit:DataGridTemplateColumn.HeaderTemplate>
<DataTemplate >
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" LastChildFill="False">
<TextBlock x:Name="TextBlockHeaderZeile1" Text="Ist" DockPanel.Dock="Top" />
<WrapPanel DockPanel.Dock="Top">
<TextBlock x:Name="TextBlockHeaderZeile2" Text=""/>
<ContentPresenter x:Name="contentPresenter">
<ContentPresenter.Content>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content" />
</ContentPresenter.Content>
</ContentPresenter>
</WrapPanel>
<Border Style="{DynamicResource borderline}">
<TextBlock VerticalAlignment="Stretch" x:Name="TextBlockSumme" Text="{Binding Path=KumulierteSummeIstVorvorjahr, Converter={StaticResource numberFormatter}, ConverterParameter='#,0.0 T€', RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cis:ChildWindow}}}"
/>
</Border>
</DockPanel>
</DataTemplate>
</toolkit:DataGridTemplateColumn.HeaderTemplate>
</toolkit:DataGridTemplateColumn>
Now I want to make a StandartTemplate for this Type because I've got many Colums like this, with only differ in the bindings of the texts in the colums as well as in their headers.
As far I've tried to make a Style for this, but this won't work, I tried to create an usercontrol (but I think it's like taking a sledgehammer to crack a nut).
So any help or hint how to solve this problem would be appreciated.
I don't see why you've rejected the UserControl approach. UserControls are pretty lightweight. They add very little overhead at runtime. They are an extra feature in your project of course, but I usually find that to be an improvement - WPF projects with a small number of large Xaml files are typically hard to maintain.
Far from being a 'sledgehammer', they seem like exactly the right solution here to me.
Add the DataTemplate into the Resources and then access it via a StaticResource
<Window>
<Window.Resources>
<DataTemplate x:Key="MyColumnTemplate">
...
</DataTemplate>
<DataTemplate x:Key="MyColumnTemplateHeader">
...
</DataTemplate>
</Window.Resources>
...
<toolkit:DataGridTemplateColumn x:Name="DataGridTextColumnIstVorvorjahr" IsReadOnly="True" SortMemberPath="SummeIstVorvorjahr"
CellTemplate={StaticResource MyColumnTemplate}
HeaderTemplate={StaticResource MyColumnTemplateHeader}
...
</Window>
If I understand you, you try to bind the same column template with different data and to have different header's content relative with column data. So, you may use "dynamic XAML" (XAML used in C# code - that is dynamic) which allows you to use one template for different data.
Here a simple example.
In C# code we create DataGridTemplateColumn object:
DataGridTemplateColumn tc = new DataGridTemplateColumn();
Then we set the CellTemplate property with template which is created dynamically in special function:
tc.CellTemplate = (DataTemplate)XamlReader.Parse(GetTextCellDataTemplate(someText));
Here is a special function which creates our template:
public static string GetTextCellDataTemplate(string bindingPath)
{
return #"
<DataTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" >
<ScrollViewer MaxHeight=""200"" MaxWidth=""250"" VerticalScrollBarVisibility=""Auto"">
<TextBlock Text=""{Binding Path=" + bindingPath + #"}""
TextWrapping=""Wrap"" />
</ScrollViewer>
</DataTemplate>";
}
Now you may send various information in this function as text and get the same template. You may choose the template from the information you want to put in the cell. For this you must write various function which will return various templates.
The same approach can be applied to header template.

Resources