Binding collection to ComboBox in Listview - wpf

I have a ListView whose DataTemplate consists of a ComboBox and some TextBoxes.
The ComboBox is bound to a Collection which is mapped to a CollectionViewSource.
The ListView can have any number of rows.
The problem is that selecting an item in one ComboBox changes them all. I do want them all to be populated with the same contents, but to be able to be set independently.
The Resources section contains the following:
<CollectionViewSource Source="{Binding ChildAccounts}" x:Key="ChildGroupedData">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="group"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<!-- Template for each child item in ListView -->
<DataTemplate x:Key="ChildTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="130"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="210"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Account" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="{StaticResource CustomWhite}" FontSize="14" Width="80"/>
<ComboBox Grid.Column="1" SelectedValue="{Binding Path=accFrom}" ItemsSource="{Binding Source={StaticResource ChildGroupedData}}" ItemTemplate="{StaticResource AccountTemplate}" SelectedValuePath="ID" Width="120" Style="{StaticResource RoundedComboBox}" HorizontalAlignment="Left" VerticalAlignment="Center">
<ComboBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource CustomExpanderComboGroupItemStyle}" HeaderTemplate="{StaticResource GroupHeader}"/>
</ComboBox.GroupStyle>
</ComboBox>
<Label Grid.Column="2" Content="Amount" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="{StaticResource CustomWhite}" FontSize="14" Width="80"/>
<TextBox Grid.Column="3" Text="{Binding Path=amount, StringFormat='#,##0.00'}" Style="{StaticResource RoundedTextBox}" Width="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Label Grid.Column="4" Content="Comment" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="{StaticResource CustomWhite}" FontSize="14" Width="80"/>
<TextBox Grid.Column="5" Text="{Binding Path=comment}" Style="{StaticResource RoundedTextBox}" Width="200" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
<!-- ListView template -->
<Style x:Key="ChildListViewStyle" TargetType="{x:Type ListView}">
<Setter Property="ItemTemplate" Value="{DynamicResource ChildTemplate}"/>
<Setter Property="Background" Value="{StaticResource CustomBackground}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="10,10,10,10"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Padding" Value="0,0,50,0"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Style.Resources>
<!-- Makes selection invisible when focus lost -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{StaticResource CustomBackgroundC}"/>
</Style.Resources>
</Style>
The ListView is defined as:
<ListView Grid.Column="0" x:Name="lstChildren" Margin="20,30,0,0" ItemsSource="{Binding Path=Items}" Style="{StaticResource ChildListViewStyle}"/>
EDIT:
The following is found in the associated class
Imports System.Data
Imports System.Data.OleDb
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Class ItemView
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
....
Private _ChildAccounts As ObservableCollection(Of AccountEntry)
Public Property ChildAccounts As ObservableCollection(Of AccountEntry)
Get
Return _ChildAccounts
End Get
Set(value As ObservableCollection(Of AccountEntry))
_ChildAccounts = value
End Set
End Property
....
Private Sub ItemView_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
Dim dsacmd As OleDbDataAdapter
Dim dsa As New DataSet
Dim dva As DataView
Dim strSelect As String
Try
' ** Open a connection to the database.
cn = New OleDbConnection(strConnection)
cn.Open()
Me.DataContext = Me
strSelect = "SELECT Accounts.ID, Accounts.deleted, Accounts.accType, Accounts.currency as curr, IIf([Currencies.ID]=1,Accounts.comment,Accounts.comment & "" ("" & Currencies.symbol & "")"") AS comment, Currencies.comment AS currS FROM Currencies INNER JOIN Accounts ON Currencies.ID = Accounts.currency"
dsacmd = New OleDbDataAdapter(strSelect, cn)
dsacmd.Fill(dsa, "Accounts")
dva = New DataView(dsa.Tables("Accounts"))
dva.RowFilter = "accType=" & cVirtual.ToString & " AND deleted=False"
dva.Sort = "curr, comment"
ChildAccounts = New ObservableCollection(Of AccountEntry)(dva.ToTable.AsEnumerable().[Select](Function(i) New [AccountEntry](i("ID"), i("currS").TrimEnd(" "), i("comment"))))
....
Private Sub DisplayItem()
....
strSelect = ""
Dim Relations As Collection(Of Relation) = GetRelations(ID)
For Each r As Relation In Relations
strSelect &= "ID=" & r.ID.ToString & " OR "
Next
If strSelect <> "" Then strSelect = "SELECT * FROM Items WHERE " & strSelect.Substring(0, strSelect.Length - 4)
If strSelect <> "" Then
dsrcmd = New OleDbDataAdapter(strSelect, cn)
dsr.Clear()
dsrcmd.Fill(dsr, "Items")
lstChildren.DataContext = dsr
End If
....

You will need to move your CollectionViewSource into the DataTemplate. To force all combobox-items to use the same Source Collection I think you can try two things:
One - Use Relative Source to pick the ChildAccounts from ListView's DataContext
...
<Grid.Resources>
<CollectionViewSource x:Key="ChildGroupedData"
Source="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}},
Path=DataContext.ChildAccounts}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="group" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
...
Update:
Above method can be seen in This sample I put together. Note that ChildAccount's is just an ObservableCollection<T> in the view-model, this is so that we are not having a new collection per ListBoxItem but share em across like what you had asked for in the question.
If your ChildAccounts property is actually like say the "comment" property where you have a ChildAccounts property object per ListBoxItem, just change
<CollectionViewSource x:Key="ChildGroupedData"
Source="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}},
Path=DataContext.ChildAccounts}">
to
<CollectionViewSource x:Key="ChildGroupedData"
Source="{Binding ChildAccounts}">
and it should work as well. You do however now have a ChildAccounts collection per ListBoxItem and aren't sharing their source.
Main thing is to Define the CollectionViewSource inside the DataTemplate. Download the attached sample and try it for yourself and check the specifics.
Two - Have ChildAccounts as a static variable
...
<Grid.Resources>
<CollectionViewSource x:Key="ChildGroupedData"
Source="{x:Static local:ChildAccounts}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="group" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
...

You can add set IsSynchronizedWithCurrentItem="False" to the combo box.

Related

Bind Element to different DataContext property

forgive this question - just learning WPF and it's making my brain hurt. Can't get my head around Bindings/DataContexts. XAML below produced via some code monkery (my knowledge of WPF not good enough atm to know what is helpful to post or not):
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:MoveResize" WindowStartupLocation="CenterScreen"
xmlns:paz="clr-namespace:Wpf.Controls.PanAndZoom;assembly=Wpf.Controls.PanAndZoom"
Title="Move and resize" Height="550" Width="750" Loaded="Window_Loaded" KeyDown="Window_KeyDown" KeyUp="Window_KeyUp">
<Window.Resources>
<!-- Custom Thumb Style-->
<Style x:Key="SliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle x:Name="Rectangle" StrokeThickness="1" Stretch="Fill" Opacity="1">
<Rectangle.Stroke>
<SolidColorBrush Color="Black"></SolidColorBrush>
</Rectangle.Stroke>
<Rectangle.Fill>
<SolidColorBrush Color="Yellow"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- MoveThumb Template -->
<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type s:MoveThumb}">
<Rectangle Fill="Transparent" />
</ControlTemplate>
<!-- ResizeDecorator Template -->
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
<Grid>
<!-- Abridged for stackoverflow posting -->
<s:ResizeThumb Style="{StaticResource SliderThumbStyle }" Width="9" Height="9" Cursor="SizeNWSE" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
</Grid>
</ControlTemplate>
<!-- Designer Item Template-->
<ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<s:MoveThumb Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll" />
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" />
<Control Template="{StaticResource ResizeDecoratorTemplate}" />
</Grid>
</ControlTemplate>
</Window.Resources>
<paz:ZoomBorder x:FieldModifier="public" Name="zoomBorder" Stretch="None" ZoomSpeed="1.2" Background="SlateBlue" ClipToBounds="True" Focusable="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="4" Grid.Column="1">
<Canvas x:Name="workspace" Background="#555" Width="1920" Height="1080" Margin="97,93,-1275,-654">
<Path x:Name="YellowDiamond" Fill="Yellow" Data="M 0,5 5,0 10,5 5,10 Z" Stretch="Fill" IsHitTestVisible="True" Canvas.Left="10" Canvas.Top="10" Height="124.75" Width="134.5" />
<ContentControl Width="130" MinWidth="50" Height="130" MinHeight="50" Canvas.Top="150" Canvas.Left="150" Template="{StaticResource DesignerItemTemplate}">
<Path x:Name="BlueDiamond" Fill="Blue" Data="M 0,5 5,0 10,5 5,10 Z" Stretch="Fill" IsHitTestVisible="False" />
</ContentControl>
<TextBox x:Name="widthTB" Height="23" Canvas.Left="131" TextWrapping="Wrap" Text="{Binding BastardWidth, Mode=OneWay}" Canvas.Top="348" Width="120" />
</Canvas>
</paz:ZoomBorder>
</Window>
The key line is:
<s:ResizeThumb Style="{StaticResource SliderThumbStyle }" Width="9" Height="9" Cursor="SizeNWSE" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
I'm wanting to set Width and Height to a property stored in certain class (PanAndZoomController). My understanding is that this is presently databound to ResizeThumb.vb. The relevant code behind:
Partial Public Class MainWindow
Private _panZoomControl As New PanAndZoomController
Public Property PanZoomController() As PanAndZoomController
Get
Return _panZoomControl
End Get
Set(ByVal value As PanAndZoomController)
_panZoomControl = value
End Set
End Property
Public Sub New()
InitializeComponent()
End Sub
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Me.DataContext = _panZoomControl
End Sub
Private Sub MousewheelMoved(sender As Object, e As MouseWheelEventArgs) Handles Me.MouseWheel
_panZoomControl.ZoomFactor = zoomBorder.ZoomX
End Sub
End Class
Public Class PanAndZoomController
Private _zoomFactor As Double
Public Property ZoomFactor() As Double
Get
Return _zoomFactor
End Get
Set(ByVal value As Double)
_zoomFactor = value
_scaledWidth = 10 * _zoomFactor
End Set
End Property
Private _scaledWidth As Double = 10
Public Property ScaledWidth() As Double
Get
Return _scaledWidth
End Get
Set(ByVal value As Double)
_scaledWidth = value
End Set
End Property
End Class
Thus, Width and Height should be populated from MainWindow.PanZoomController.ScaledWidth. Could someone help out with how to achieve this? In as little XAML as possible, please!? I still need to preserve the binding of that element to s:ResizeThumb due to the code behind.
EDIT: In response to ASh's suggestions.
I've tried NotifyPropertyChanged with what I think is the right way, but still no joy :(
Simplified code scenario. Relevant code behind:
Public Class Workspace
Implements INotifyPropertyChanged
Public Sub NotifyPropertyChanged(ByVal propName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _canvasZoomFactor As Double = 1
Public Property CanvasZoomFactor() As Double
Get
Return _canvasZoomFactor
End Get
Set(ByVal value As Double)
_canvasZoomFactor = value
_handleWidth = 5 * value
Me.NotifyPropertyChanged("HandleWidth")
End Set
End Property
Private _handleWidth As Double = 5
Public ReadOnly Property HandleWidth() As Double
Get
Return _handleWidth
End Get
End Property
End Class
XAML:
<UserControl x:Name="MainWorkspace" x:Class="Workspace"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="clr-namespace:stigzler.utility.WPFcontrols"
xmlns:local="clr-namespace:stigzler.utility.WPFcontrols"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
<Grid SnapsToDevicePixels="false">
<s:ResizeThumb Width="{Binding ElementName=Workspace, Path=HandleWidth,UpdateSourceTrigger=PropertyChanged}"
Height="{Binding ElementName=Workspace, Path=HandleWidth,UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SliderThumbStyle}" Cursor="SizeNWSE" VerticalAlignment="Top"
HorizontalAlignment="Left" />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" />
<Control Template="{StaticResource ResizeDecoratorTemplate}" />
</Grid>
</ControlTemplate>
<ContentControl Width="130" MinWidth="50" Height="130" MinHeight="50" Canvas.Top="150" Canvas.Left="150" Template="{StaticResource DesignerItemTemplate}">
<Path x:Name="BlueDiamond" Fill="Blue" Data="M 0,5 5,0 10,5 5,10 Z" Stretch="Fill" IsHitTestVisible="False" />
</ContentControl>
</UserControl>
Relevant lines:
<s:ResizeThumb Width="{Binding ElementName=Workspace, Path=HandleWidth,UpdateSourceTrigger=PropertyChanged}"
Me.NotifyPropertyChanged("HandleWidth")
Still getting no joy. Any other suggestions (I'm still really struggling to get my head around this binding lark).
"My understanding is that this is presently databound to ResizeThumb.vb" - there can't be a binding to a file with code.
Each binding must have a source to get values. There are some options to provide that source:
specify it directly, e.g.: "{Binding Source={StaticResource}}";
use DataContext - the default option: "{Binding Path=SomeProperty}" - when no source is provided, then the binding will try to find requested property in a DataContext - some data associated with the View (or with part of the View - one might want to work with different data in different parts). Usually there is one DataContext per view (Me.DataContext = _panZoomControl)
use other element as binding source (via RelativeSource or ElementName), if the element are in the same view.
s:ResizeThumb is inside MainWindow view, so RelativeSource should work:
<s:ResizeThumb Style="{StaticResource SliderThumbStyle}"
Width="{Binding Path=PanZoomController.ScaledWidth, RelativeSource={RelativeSource AncestorType = {x:Type s:MainWindow}}}"
Height="{Binding Path=PanZoomController.ScaledWidth, RelativeSource={RelativeSource AncestorType = {x:Type s:MainWindow}}}"
hint: when binding doesn't work for some reason, check Output window in Visual Studio - there can be a message describing binding problem (type mismatch, missing property, incorrect DataContext are common reasons)
In addition to #ASh's answer (+1) on how to actually bind to the properties, you should also implement the INotifyPropertyChanged interface in your PanAndZoomController class in order for the view to be refreshed whenever you set the ZoomFactor and ScaledWidth properties dynamically:
Public Class PanAndZoomController
Implements INotifyPropertyChanged
Private _zoomFactor As Double
Public Property ZoomFactor() As Double
Get
Return _zoomFactor
End Get
Set(ByVal value As Double)
_zoomFactor = value
NotifyPropertyChanged(NameOf(ZoomFactor))
ScaledWidth = 10 * _zoomFactor
End Set
End Property
Private _scaledWidth As Double = 10
Public Property ScaledWidth() As Double
Get
Return _scaledWidth
End Get
Set(ByVal value As Double)
_scaledWidth = value
NotifyPropertyChanged(NameOf(ScaledWidth))
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub NotifyPropertyChanged(info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
End Class

WPF listbox groupping by substrings

My object has property that stores more strings separated by separator.
I want to display list of such objects in WPF listbox with grouping enabled. What I need is to have groups according to substrings.
Object1: Property = "string1;string2;string3"
Object2: Property = "string2;string3"
I expect listbox to be displayed like that:
string1
Object 1
Object 2
string2
Object 1
string3
Object 1
Object 2
Is that possible?
Thank you for your help.
Create a wrapper class.
class MyGroup
{
public string GroupID;
public object SomeObject;
}
Build your flat list of that wrapper class.
private List<MyGroup> BuildItemsSourceTogether()
{
List<MyGroup>itemsSource = new List<MyGroup>();
foreach(var obj in myListWithObjectsWhichPropertiesAreStringsWhichFuthermoreContainSubstrings)
{
var stringArray = obj.Property123.Split(';');
foreach(var str in stringArray)
{
itemsSource.Add(new MyGroup () { GroupID = str, SomeObject = obj});
}
}
return itemsSource;
}
Tell what property in your wrapper class should be used for grouping.
class Window1
{
public Window1()
{
InitalizeComponents();
var finalData = new ListCollectionView(BuildItemsSourceTogether());
finalData.GroupDescriptions.Add(new PropertyGroupDescription("GroupID"));
this.DataContext = finalData;
}
}
In XAML set the look of your groups and let WPF group that flat list of IDs for you.
I used a DataGrid with columns. You can use a ListBox.
<DataGrid ItemsSource="{Binding}">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text="Items"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="header1" Binding="{Binding SomeObject.Property321}" />
<DataGridTextColumn Header="header2" Binding="{Binding SomeObject.Property678}" />
</DataGrid.Columns>
</DataGrid>
Have fun.

WPF:change background color of listview item

how to change the foreground(even Background will do) of item in listview.
i have a program which opens excel and check for broken links in the given sheet.
i want to display the user the list of given links and whcih ever is broken. i want to change foreground to RED.
i have bound the values to observablecollection. the collection is just collection of strings(WEB LINKS) and is working fine
should i do multi binding like here
EDIT:-
have got one more problem on this. after creating the property and making all the changes. the WPF form is not getting updated with the values. i.e. the list box is not getting filled. neither the coloring is happening( not sure it is happening also. as i cant see them).
here is my code. please excuse my coding i am new to WPF
<Window x:Class="URLValide.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Local="clr-namespace:URL_Validater.URLValide"
Title="URL Validator" Height="269" Width="525" FontSize="13"
ResizeMode="NoResize">
<Window.Resources>
<ResourceDictionary>
<Style x:Key="HighLight" TargetType="{x:Type Control}">
<Setter Property="Background" Value="Honeydew"/>
<Setter Property="FontWeight" Value="UltraBlack"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="40" Color="Beige" Direction="50" Opacity="0.5"/>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Window.Resources>
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Name="WinHeader" Height="30" Background="BurlyWood" FontFamily="Calibri" FontSize="20" FontWeight="Bold" FontStretch="Medium" VerticalAlignment="Top" HorizontalAlignment="Stretch" Margin="0,0,0,0" HorizontalContentAlignment="Center" VerticalContentAlignment="Top">URL Validator</Label>
<Grid DockPanel.Dock="Bottom" Background="Beige">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" MaxHeight="30"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="Current URL:"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding strCrnUrl}" Width="370"></TextBlock>
<TextBlock Grid.Column="2" Text="10 of 100" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>
</Grid>
<Grid DockPanel.Dock="Right" Width="154">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="300" Width="19*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="55" MinHeight="10" Height="35*" />
<RowDefinition Height="165*" MinHeight="10" />
</Grid.RowDefinitions>
<Label Name="LbleRight" BorderBrush="Black" BorderThickness="1" Margin="0,2" FontSize="13" Content="List Of URL's" Height="30" Grid.ColumnSpan="2" Grid.Row="0"></Label>
<ListView Grid.Row="1" Background="Azure" ItemsSource="{Binding strPdfLst}" IsEnabled="True" Margin="0,0,0,1"></ListView>
</Grid>
<Grid DockPanel.Dock="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30*" />
<RowDefinition Height="60*" />
</Grid.RowDefinitions>
<Label BorderBrush="Black" Name="lblFleSel" BorderThickness="1" Height="27" Margin="2,2,0,30" HorizontalAlignment="Left" Width="349">Select File To which Contains the list of URL's:</Label>
<TextBox Name="txtbxFleNme" BorderBrush="Black" BorderThickness="1" Margin="2,34,0,0" Style="{StaticResource ResourceKey=HighLight}" HorizontalAlignment="Left" Width="272"></TextBox>
<Button Name="btnFleSlec" Width="69" Height="27" Content="Browse" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="276,32,4,0"></Button>
<Grid Grid.Row="1" Height="118" HorizontalAlignment="Left" Margin="0,1,0,0" Name="OptionGrid" VerticalAlignment="Top" Grid.RowSpan="2">
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1" Height="117" Margin="3,1,0,0" HorizontalAlignment="Stretch" Width="350">
<!--<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Width="162" Height="118">
</StackPanel>-->
<Grid Height="auto" HorizontalAlignment="Stretch" Width="335">
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<CheckBox Name="chkboxHas" VerticalAlignment="Center" HorizontalAlignment="Center">Has Column Headers</CheckBox>
<Label Name="lblDesc" Height="auto" Margin="0,0,204,0" Grid.Row="1" HorizontalContentAlignment="Right" VerticalAlignment="Top">Description Column:</Label>
<ComboBox Grid.Row="1" Name="cmboxDescol" Margin="131,0,0,0" Style="{StaticResource ResourceKey=HighLight}"></ComboBox>
<Label Name="lblUrlCol" Height="auto" Grid.Row="2" Margin="0,0,204,0" HorizontalContentAlignment="Right">URL's Column:</Label>
<ComboBox Name="cmboxUrlCol" Grid.Row="2" Margin="131,0,0,0" Style="{StaticResource ResourceKey=HighLight}"></ComboBox>
<Label Name="lblResCol" Height="auto" Grid.Row="3" Margin="0,0,196,0" HorizontalContentAlignment="Right">Result Column:</Label>
<ComboBox Name="cmboxResCol" Grid.Row="3" Margin="131,0,0,0" Style="{StaticResource ResourceKey=HighLight}"></ComboBox>
<Button Grid.Row="4" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Validate URL links" Name="btnValidate"></Button>
</Grid>
</Border>
</StackPanel>
</Grid>
</Grid>
</DockPanel>
i am not sure if i should be posting full code. but here is my class
the button click will start the program.
My class code:-
Imports Microsoft
Imports System
Imports System.Net
Imports System.Data
Imports System.Windows
Imports System.Windows.Forms
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Namespace URLValide
Public Class clsUrlCheck
Implements INotifyPropertyChanged
Public Event propertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public exclApplic As New Excel.Application
Public exclWkbOpe As Excel.Workbook
Public exclWksAct As Excel.Worksheet
Public exclRngUrl As Excel.Range
Public exclRngDes As Excel.Range
Public exclRngOut As Excel.Range
Public intMaxRow As Long
Public intCrtRow As Long
Private _strTotlOf As String
Private _strCrnUrl As String
Private _ColorIndx As String
Private _strPdfLst As ObservableCollection(Of String)
Private _strhdrPdf As ObservableCollection(Of String)
#Region "Region of poperties"
Public Property strTotlOf() As String
Get
Return _strTotlOf
End Get
Set(ByVal value As String)
_strTotlOf = value
Me.OnPropertyChanged("strTotlOf")
End Set
End Property
Public Property strCrnUrl() As String
Get
Return _strCrnUrl
End Get
Set(ByVal value As String)
_strCrnUrl = value
Me.OnPropertyChanged("strCrnUrl")
End Set
End Property
Public Property strPdfLst As ObservableCollection(Of String)
Get
Return _strPdfLst
End Get
Set(ByVal value As ObservableCollection(Of String))
_strPdfLst = value
Me.OnPropertyChanged("strPdfLst")
End Set
End Property
Public Property strhdrPdf As ObservableCollection(Of String)
Get
Return _strhdrPdf
End Get
Set(ByVal value As ObservableCollection(Of String))
_strhdrPdf = value
Me.OnPropertyChanged("strhdrPdf")
End Set
End Property
Public Property ColorIndx As String
Get
Return _ColorIndx
End Get
Set(ByVal value As String)
_ColorIndx = value
Me.OnPropertyChanged("ColorIndx")
End Set
End Property
Private Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent propertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
#End Region
#Region "function of Validating the URL's"
Public Function UrlCheck(ByVal strUrlReq As String)
Try
Dim WebReq As Net.HttpWebRequest = Net.HttpWebRequest.Create(strUrlReq)
WebReq.Method = "Head"
WebReq.Timeout = 5000
Using Response = WebReq.GetResponse()
Return True
End Using
Catch ex As Exception
ColorIndx = "True"
Return False
End Try
End Function
#End Region
#Region "Start Function"
Sub suStart()
Dim blnValid As Boolean
'strPdfLst.Clear()
'strPdfLst = makeList(exclRngUrl.Column, False)
If exclRngDes.Value = "Make Desc" Then
strPdfLst = makeList(exclRngUrl.Column, True)
exclRngDes.Delete()
Else
strPdfLst = makeList(exclRngUrl.Column, False)
End If
For Each exclRngEch As Excel.Range In exclRngUrl
strCrnUrl = exclRngEch.Text
strTotlOf = exclRngEch.Row & "OF" & intMaxRow
blnValid = UrlCheck(exclRngEch.Value.ToString)
If blnValid Then
exclWksAct.Cells(exclRngEch.Row, exclRngOut.Column).value = "Web Page Present"
Else
exclWksAct.Cells(exclRngEch.Row, exclRngOut.Column).value = "Web Page Error"
End If
Next
End Sub
Function makeList(ByVal intColNum As Long, ByVal blnMkeStr As Boolean) As ObservableCollection(Of String)
Dim ObsColTem As ObservableCollection(Of String) = New ObservableCollection(Of String)
If Not blnMkeStr Then
For intLopCnt As Int32 = intCrtRow To intMaxRow
ObsColTem.Add(exclWksAct.Cells(intLopCnt, intColNum).Text)
Next
Else
For intLopCnt As Int32 = intCrtRow To intMaxRow
Dim strDesc As String = Mid(exclWksAct.Cells(intLopCnt, intColNum).Text, InStrRev(exclWksAct.Cells(intLopCnt, intColNum).Text, "/", , CompareMethod.Text) + 1)
ObsColTem.Add(strDesc)
Next
End If
Return ObsColTem
End Function
#End Region
End Class
End Namespace
This is from working code
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RowSelected}" Value="True">
<Setter Property="Background" Value="Gainsboro" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
create a converter which takes the link as parameter and send the background/foreground color, the converters checks the link and sends the correct code accordingly,bind the color code to the itemtemplate background/foreground property.
First create a Broken-Property which you can bind to and then just create a Style for ListViewItems with a DataTrigger on the Broken-Property!
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Broken}" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
Have not tested this code but it should work!

Custom templated combobox with special non templated item

I have a RadTreeView, in each item there is a RadCombobox with some elements. Now I need to add some "special" item into each combobox. User can click on this item to add new element in combobox:
My current code:
<DataTemplate x:Key="Monitor">
<Grid Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Height="16" Width="16" Source="icons\monitor.png" />
<TextBlock Text="{Binding Name}" Margin="5 0 0 0" Grid.Column="1" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<!-- PROBLEM IS HERE -->
<telerik:RadComboBox Name="RadComboSchedule"
Grid.Column="2"
Margin="10 0 0 0"
Width="155"
ItemsSource="{Binding Source={StaticResource DataSource}, Path=ScheduleDataSource}"
ItemTemplate="{StaticResource ComboBoxTemplate}"
>
</telerik:RadComboBox>
<Button Name="BtnRemoveMonitor" Grid.Column="3" Style="{StaticResource ButtonListBoxItemStyle}" Template="{StaticResource RemoveButtonTemplate}" />
</Grid>
</DataTemplate>
<HierarchicalDataTemplate x:Key="Group"
ItemTemplate="{StaticResource Monitor}"
ItemsSource="{Binding Monitors}">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</HierarchicalDataTemplate>
<telerik:RadTreeView
Name="RadTreeViewGroups"
Height="auto"
Width="auto"
ItemsSource="{Binding Source={StaticResource DataSource}, Path=GroupsDataSource}"
ItemTemplate="{StaticResource Group}"
>
</telerik:RadTreeView>
So, I have all like at a screenshot without element "Add new item".
Any ideas?
PS It's not a problem to use standard WPF Combobox and TreeView controls.
You can create a new item in the DataSource of the ComboBox which name is "ADD NEW ITEM" and handle when the user select it.
private void SelectItem(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems[0].ToString() == "new")
{
string newItem = "completely new item";
dataSource.Add(newItem);
((ComboBox)sender).SelectedItem = newItem;
}
}
In this question you can see a better example that each item is an instance of a class, so it's easier to handle the "add item" request:
Databound WPF ComboBox with 'New...' item
Edit (about the 'add item' button template):
Based on the example above
Having this class
public class DisplayClass
{
public string Name { get; set; }
public bool IsDummy { get; set; }
}
You bind ComboBox.ItemsSource to an ObservableCollection like this one:
public ObservableCollection<DisplayClass> DataSource { get; set; }
Add that "dummy" item to the collection
DataSource.Add(new DisplayClass { Name = "ADD ITEM", IsDummy = true });
Then you handle the item selection with something like this:
private void SelectItem(object sender, SelectionChangedEventArgs e)
{
var comboBox = (ComboBox)sender;
var selectedItem = comboBox.SelectedItem as DisplayClass;
if (selectedItem != null && selectedItem.IsDummy)
{
//Creating the new item
var newItem = new DisplayClass { Name = comboBox.Items.Count.ToString(), IsDummy = false };
//Adding to the datasource
DataSource.Add(newItem);
//Removing and adding the dummy item from the collection, thus it is always the last on the 'list'
DataSource.Remove(selectedItem);
DataSource.Add(selectedItem);
//Select the new item
comboBox.SelectedItem = newItem;
}
}
To display the items properly, you'll need to change the ComboBox.ItemTemplate, making the image invisible when the item is dummy
<ComboBox ItemsSource="{Binding DataSource}" SelectionChanged="SelectItem">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Width="180" />
<Image HorizontalAlignment="Right" Source="..." MouseLeftButtonUp="DeleteItem">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding IsDummy}" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

List the items in listview according to groups, the data is taken from observable collection

i hav one class which stores file information with namelist as itz observableCollection
Imports System.Collections.ObjectModel
Public Class NameList
Inherits ObservableCollection(Of FileInfo)
' Methods
Public Sub New()
MyBase.Add(New FileInfo("Willa", "Cather", "warning", "err 1"))
MyBase.Add(New FileInfo("Isak", "Dinesen", "warning", "err 1"))
MyBase.Add(New FileInfo("Victor", "Hugo", "warning", "err 1"))
MyBase.Add(New FileInfo("Jules", "Verne", "warning", "err 3"))
MyBase.Add(New FileInfo("Victor", "Hugo", "warning", "err 1"))
MyBase.Add(New FileInfo("Jules", "Verne", "warning", "err 3"))
End Sub
End Class
Public Class FileInfo
Public _name As String
Public _path As String
Public _image As String
Public _errorGrp As String
Public Property ImageIcon() As String
Get
Return _image
End Get
Set(ByVal value As String)
_image = value
End Set
End Property
Public Property PathFile() As String
Get
Return _path
End Get
Set(ByVal value As String)
_path = value
End Set
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property ErrorGroup As String
Get
Return _errorGrp
End Get
Set(ByVal value As String)
_errorGrp = value
End Set
End Property
Public Sub New(ByVal fileName As String, ByVal filePath As String, ByVal image As String, ByVal errorGrp As String)
Name = fileName
PathFile = filePath
ImageIcon = image
ErrorGroup = errorGrp
End Sub
End Class
i need to bind this to the xaml listview item which will be grouped according to errorGroup
i code which i have tried is
<Window.Resources >
<mydata:NameList x:Key="NameListData"/>
<!-- <DataTemplate x:Key="IconListViewItem" >
<StackPanel Orientation="Horizontal" >
<Image Source="/listViewGroupin;component/Images/ViewType.jpg" Height="19" Width="25" ></Image>
<TextBlock Foreground="DarkBlue" Text="{Binding ImageIcon}"/>
<TextBlock Foreground="DarkBlue" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>-->
<CollectionViewSource x:Key='src'
Source="{Binding Source={StaticResource NameListData}}">
<CollectionViewSource.GroupDescriptions>
<!-- <PropertyGroupDescription PropertyName="ErrorGroup" />-->
<PropertyGroupDescription PropertyName="ErrorGroup"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Source={StaticResource src}}"
IsSynchronizedWithCurrentItem="True" >
<ListView.GroupStyle >
<GroupStyle >
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<GroupBox BorderBrush="Transparent" >
<GroupBox.Header >
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Name}"
Margin="5,0,0,0" Width="100"/>
<Border Height=".2" Width="300" Background="Blue" ></Border>
</StackPanel>
</GroupBox.Header>
</GroupBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Width" Value="Auto" />
<Setter Property="FontSize" Value="10.4" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View >
<GridView AllowsColumnReorder="False">
<GridViewColumn Width=" 250" Header="File" DisplayMemberBinding="{Binding Name }">
</GridViewColumn>
<GridViewColumn Header="Path" Width="350" DisplayMemberBinding="{Binding PathFile}">
</GridViewColumn>
<GridViewColumn Header="Error" Width="350" DisplayMemberBinding="{Binding ErrorGroup}">
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
it is giving me only group names and groups but not the item
please help me
You have defined your ListView.GroupStyle as a GroupBox.
GroupBox is a HeaderedContentControl.
You have defined the Group Header, but you also need to define a placeholder for the items -
<GroupBox.Content>
<ItemsPresenter />
</GroupBox.Content>

Resources