WPF Hide an Item of a Combobox ItemSource - wpf

In my WPF View, I have a DataGrid which Display Data from a Database.
One column is a combobox that is bound to a string in Database.
This is the list of available string :
public List<string> AvailableTypeImpression { get; } = new List<string>() {"S","D","T","X","M","p","P","R"}
All these string could be displayed in the datagrid, but if the user want to edit it, I can only set S, D, T, or X. The user is not allowed to set M, p, P or R.
So I would like to hide these four letter from the combobox available Items. But I don't really know how to do that in a simple way (I found some solution on Stack Overflow but it doesn't work in my case).
Here's the code of my datagrid :
<DataGrid Grid.Row="1" x:Name="LotsListDataGrid" IsReadOnly="False" SelectionMode="Single" SelectionUnit="FullRow" SelectedItem="{Binding SelectedLot}" ItemsSource="{Binding FilteredList}" VirtualizingPanel.IsVirtualizing="True" EnableRowVirtualization="True" HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Lot" Width="200" Binding="{Binding Value.Lot.Intitule}" IsReadOnly="True"/>
<DataGridTemplateColumn Header=".i." HeaderStyle="{StaticResource CenteredColumnHeaderStyle}" Width="545" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}">
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
FilteredList.Value.Lot.TypeImpression is a string.
If I've well understood, all the possible string must be in the ItemSource otherwise they could'nt be displayed. But I need to find a way to prevent user to select some of them.
Thanks for your help.

I don't know of a way to make individual items non-selectable in a combo box.
But you could always show a combo box without your not-allowed letters (i.e. remove them from AvailableTypeImpression), and instead show just a simple TextBlock in your cell in case one of these letters is read from the DB.
Change your cell template to something like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox Visbility="{Binding IsValueEditable}" Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Visbility="{Binding NotIsValueEditable}" Height="23" Text="{Binding Value.Lot.TypeImpression}" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Then implement IsValueEditable, NotIsValueEditable properties in your ViewModel such that only one of the controls is shown.
Alternatively, if you also want to be able to modify existing entries of M, p, P, R, you could use a DataGridTemplateColumn.CellEditingTemplate:
Make the CellEditingTemplate show the ComboBox (without M, p, P, R options) while the regular CellTemplate only contains a TextBlock.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="23" Text="{Binding Value.Lot.TypeImpression}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Height="23" Style="{StaticResource AnfComboBoxStyle}" ItemsSource="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedItem="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

The solution from #dheller was good but not working in my case because the user is not able to give to "Value.Lot.TypeImpression" a new Value M ,p, P or R, but he's able to edit "Value.Lot.TypeImpression" even if it equals to M ,p, P or R and set S, D, T, or X.
So I've found another way :
In my ViewModel I've defined a new class :
public class TypeImpressionAvailable
{
public string Name { get; set; }
public bool IsAvailable { get; set; }
}
And my list to give to my combobox as ItemSource :
public List<TypeImpressionAvailable> AvailableTypeImpression { get; } = new List<TypeImpressionAvailable>() {
new TypeImpressionAvailable(){ Name="N", IsAvailable=true },
new TypeImpressionAvailable(){ Name="S", IsAvailable=true },
new TypeImpressionAvailable(){ Name="D", IsAvailable=true },
new TypeImpressionAvailable(){ Name="T", IsAvailable=true },
new TypeImpressionAvailable(){ Name="X", IsAvailable=true },
new TypeImpressionAvailable(){ Name="M", IsAvailable=false },
new TypeImpressionAvailable(){ Name="p", IsAvailable=false },
new TypeImpressionAvailable(){ Name="P", IsAvailable=false },
new TypeImpressionAvailable(){ Name="R", IsAvailable=false }
};
And in my View :
<DataGridTemplateColumn Header=".i." HeaderStyle="{StaticResource CenteredColumnHeaderStyle}" Width="45" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Height="23" SelectedValuePath="Name" DisplayMemberPath="Name"
SelectedValue="{Binding Value.Lot.TypeImpression, UpdateSourceTrigger=PropertyChanged}"
>
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource AnfComboBoxStyle}">
<Setter Property="ItemsSource" Value="{Binding DataContext.AvailableTypeImpression, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAvailable}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
</ComboBox.Style>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
And it works fine :)

Related

Pass values to ValueConverter from two different binding sources in single DataGrid

What I want to do is to color DataGridRow red if validation fails. I attempted to do so with ValueConverter but I have no idea how to pass value from more than one binding source.
I've got datagrid with binding to collection of objects. Then there's a
DataGridTemplateColumn with ComboBox and Textbox inside (only one is visible at time), and the ComboBox has non related to bound collection binding source.
See code:
<DataGrid Grid.Row="4" Grid.Column="0" x:Name="DGR_Slots" Grid.ColumnSpan="5" Grid.RowSpan="3" ItemsSource="{Binding ElementName=WND_ItemCraftingWindow, Path=SelectedSchematic.Slots}" AutoGenerateColumns="False" ColumnWidth="*">
<DataGrid.Resources>
<classes:ValidationConverter x:Key="ValidationConverter" />
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="{Binding Converter={StaticResource ValidationConverter}}" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Id}" Visibility="Collapsed"/>
<DataGridTextColumn Header="Slot Type" Binding="{Binding SlotType}" />
<DataGridTextColumn Header="Mat Type" Binding="{Binding MaterialType}" />
<DataGridTextColumn Header="Count" Binding="{Binding MaterialCount}" />
<!--<DataGridComboBoxColumn Header="Material" />-->
<DataGridTemplateColumn Header="Material">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox Visibility="Visible" MouseDoubleClick="MaterialCell_MouseDoubleClick" ItemsSource="{Binding ElementName=WND_ItemCraftingWindow, Path=Materials}" DisplayMemberPath="Name" SelectedValuePath="Name" SelectionChanged="MaterialComboBox_SelectionChanged"/>
<TextBox Visibility="Collapsed" MouseDoubleClick="MaterialCell_MouseDoubleClick" PreviewKeyUp="MaterialCell_TextBox_PreviewKeyUp" KeyUp="MaterialCell_TextBox_KeyUp" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
WND_ItemCraftingWindow is the Window that owns the datagrid and the Materials is ObservableCollection property inside that window.
I need to pass the object from DataGrid.ItemsSource collection (that works now) and SelectedItem from Combobox in same row (i dont know how to do that) into ValidationConverter.
Validation of the row can be performed only with the object from DataGridRow and SelectedItem from combobox.
Also I'm open to different solutions to color the row after such validation.
Alright I managed to do it hackish way.
Datagrid code (removed meaningless parts):
<DataGrid x:Name="DGR_Slots" ItemsSource="{Binding ElementName=WND_ItemCraftingWindow, Path=SelectedSchematic.Slots}" AutoGenerateColumns="False" ColumnWidth="*" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Material">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<ComboBox Visibility="Visible" ItemsSource="{Binding ElementName=WND_ItemCraftingWindow, Path=Materials}" SelectionChanged="MaterialComboBox_SelectionChanged" />
<TextBox Visibility="Collapsed" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
SelectionChanged event
private void MaterialComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// ...
var slot = (DGR_Slots.SelectedItem as SchematicSlot);
var mat = ((sender as ComboBox).SelectedItem as Material);
var row = WPFHelper.GetRow(DGR_Slots, DGR_Slots.SelectedIndex);
row.Background = new SolidColorBrush(slot.MaterialType != mat.MaterialType ? Colors.Red : Colors.White);
}
WPFHelper GetRow method (found somewhere on the internet)
static public DataGridRow GetRow(DataGrid dg, int index)
{
DataGridRow row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
dg.ScrollIntoView(dg.Items[index]);
row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
Although I'm still open to other solutions.

Bind combobox to collection in viewmodel

I have a combo box inside the datagrid. Datagrid is bound to an item source. I want to fill the combo box to a collection apart from its parent collection but its not working.
<data:DataGrid x:Name="dgTransferStockroomGLDetails" AutoGenerateColumns="False" ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
VerticalScrollBarVisibility="Visible" ItemsSource="{Binding StockroomTransferDetails, Mode=TwoWay}"
CanUserResizeColumns="False" VerticalAlignment="Top" RowBackground="White" AlternatingRowBackground="White" GridLinesVisibility="All" Height="400">
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Header="From Stockroom" Width="200" CanUserReorder="True" CanUserSort="True" IsReadOnly="False">
<data:DataGridTemplateColumn.HeaderStyle>
<Style TargetType="prim:DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</data:DataGridTemplateColumn.HeaderStyle>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--<TextBox Text="{Binding From_Stkrm_Id}" Width="200" Height="30" />-->
<ComboBox Width="200" Height="30" ItemsSource="{Binding WiingsStkrmList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
Here is my view model
private ObservableCollection<BuyerWebService.Stockroom> wiingsStkrmList;
public ObservableCollection<BuyerWebService.Stockroom> WiingsStkrmList
{
get
{
return wiingsStkrmList;
}
set
{
wiingsStkrmList = value;
SendChangedNotification("WiingsStkrmList");
}
}
private ObservableCollection<BuyerWebService.StockroomTransfer> stockroomTransferdetails;
public ObservableCollection<BuyerWebService.StockroomTransfer> StockroomTransferDetails
{
get
{
return stockroomTransferdetails;
}
set
{
stockroomTransferdetails = value;
SendChangedNotification("StockroomTransferDetails");
}
}
I checked the output window, it says
'WiingsStkrmList' property not found on 'BuyerPortal.BuyerWebService.StockroomTransfer'
StockroomTransfer is used to bind the datagrid. The combo is trying to find the WiingsStkrmList in parent item source.
How to bind it to a different collection?
You need to specify a relative source for where the bound property can be found, usually by pointing at a parent element that is bound to the view model. Something like this:
ItemsSource="{Binding StockroomTransferDetails, RelativeSource={RelativeSource AncestorType=Grid}}"
Change AncestorType=Grid to something that has a datacontext of your viewmodel ... something outside of your datagrid basically.

DataGrid DataGridTemplateColumn ComboBox

I'm having trouble with my ComboBoxes in a DataGrid, let me explain with a few pictures.
This is the starting point.
Now if I want to add a new row I click the last row and hit Enter.
A new row is added and iv selected type table here and given it a name MY_TABLE, then I hit enter to add another row.
The result is this, the combobox for the previous added row's type selection has gone back to None. NOTE: that the checkboxes were previously grayed out as type None cant have any privileges, but table can have CRUD so when I selected type table they became enabled.
Here is the ViewModel (VM) for each row:
public class RoleHasPrivilegeOnObjectEntityViewModel : EntityViewModelBase<RoleHasPrivilegeOnObjectEntityViewModel, RoleHasPrivilegesOnObject>, IRoleHasPrivilegeOnObjectListItemViewModel
{
private readonly RoleHasPrivilegesOnObject _roleHasPrivilegesOnObject;
private ObservableCollection<ObjectTypeEntityViewModel> _availableObjectTypes;
private readonly ObjectTypeEntityViewModel _objectTypeEntityViewModel;
private IRoleEntityViewModel _role;
private IObjectEntityViewModel _object;
public RoleHasPrivilegeOnObjectEntityViewModel(RoleHasPrivilegesOnObject roleHasPrivilegesOnObject, IEnumerable<OBJECT_TYPE> availableObjectTypes)
{
_roleHasPrivilegesOnObject = roleHasPrivilegesOnObject;
AvailableObjectTypes = new ObservableCollection<ObjectTypeEntityViewModel>(availableObjectTypes.Select(ot => new ObjectTypeEntityViewModel(ot)));
_role = new RoleEntityViewModel(_roleHasPrivilegesOnObject.Role);
_object = new ObjectEntityViewModel(_roleHasPrivilegesOnObject.Object);
_objectTypeEntityViewModel = new ObjectTypeEntityViewModel(_roleHasPrivilegesOnObject.Object.OBJECT_TYPE);
}
public RoleHasPrivilegeOnObjectEntityViewModel(XROLE role, CONTAINER schema, OBJECT_TYPE currentObjectType, IEnumerable<OBJECT_TYPE> availableObjectTypes)
{
var objectTypes = availableObjectTypes as IList<OBJECT_TYPE> ?? availableObjectTypes.ToList();
_roleHasPrivilegesOnObject = new RoleHasPrivilegesOnObject(role,
new XOBJECT { CONTAINER = schema, OBJECT_TYPE = currentObjectType },
new List<OBJECT_HAS_PRIVILEGE>(),
objectTypes.SelectMany(aot => aot.PRIVILEGE));
AvailableObjectTypes = new ObservableCollection<ObjectTypeEntityViewModel>(objectTypes.Select(ot => new ObjectTypeEntityViewModel(ot)));
_role = new RoleEntityViewModel(_roleHasPrivilegesOnObject.Role);
_object = new ObjectEntityViewModel(_roleHasPrivilegesOnObject.Object);
_objectTypeEntityViewModel = new ObjectTypeEntityViewModel(_roleHasPrivilegesOnObject.Object.OBJECT_TYPE);
}
public override EntityType EntityType
{
get { return SelectedObjectType.EntityType; }
}
public ObjectTypeEntityViewModel SelectedObjectType
{
get { return _objectTypeEntityViewModel; }
set
{
_roleHasPrivilegesOnObject.Object.OBJECT_TYPE = value.OriginalEntity;
OnPropertyChanged();
OnPropertyChanged("CanHaveSelect");
...
}
}
public ObservableCollection<ObjectTypeEntityViewModel> AvailableObjectTypes
{
get { return _availableObjectTypes; }
set
{
_availableObjectTypes = value;
OnPropertyChanged();
}
}
public string ToolTip
{
get { return _roleHasPrivilegesOnObject.ToolTip; }
}
public bool HasSelect
{
get { return _roleHasPrivilegesOnObject.HasSelect; }
set
{
_roleHasPrivilegesOnObject.HasSelect = value;
OnPropertyChanged();
}
}
public bool CanHaveSelect
{
get
{
var canHaveSelect = _roleHasPrivilegesOnObject.CanHaveSelect;
if(!canHaveSelect && HasSelect) HasSelect = false;
return canHaveSelect;
}
}
...
public override string NAME
{
get { return _roleHasPrivilegesOnObject.NAME; }
set
{
_roleHasPrivilegesOnObject.NAME = value;
OnPropertyChanged();
OnPropertyChanged("Text");
}
}
}
And here is my View for the DataGrid
<UserControl ...
d:DataContext="{d:DesignInstance impl:PrivilegeDetailsViewModel}">
<UserControl.Resources>
<Style x:Key="DataGridContentCellCentering" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CanHaveSelectStyle" TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding CanHaveSelect, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding CanHaveSelect, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
...
</UserControl.Resources>
<DataGrid x:Name="PrivilegeDataGrid"
ItemsSource="{Binding RolesHasPrivilegesOnObjects}"
AutoGenerateColumns="False"
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserResizeRows="False"
CanUserSortColumns="True"
CanUserAddRows="True"
IsTextSearchEnabled="True"
BorderThickness="0">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" CanUserSort="True" MinWidth="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type impl2:RoleHasPrivilegeOnObjectEntityViewModel}">
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedItem="{Binding SelectedObjectType}"
SelectedValue="{Binding SelectedObjectType.ID}"
SelectedValuePath="ID">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type impl2:ObjectTypeEntityViewModel}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" ToolTip="{Binding ToolTip}" Margin="0,0,3,0" Width="17" Height="17"/>
<TextBlock Text="{Binding ToolTip}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="*" Header="Name" Binding="{Binding NAME}">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="extensions:TextBoxUpperCaseBehavior.IsEnabled" Value="True"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
<DataGridCheckBoxColumn Header="Select"
Binding="{Binding HasSelect, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
CellStyle="{StaticResource DataGridContentCellCentering}"
ElementStyle="{StaticResource CanHaveSelectStyle}"
EditingElementStyle="{StaticResource CanHaveSelectStyle}" />
...
</DataGrid.Columns>
</DataGrid>
</UserControl>
I have tried all these variants for the ComboBox ItemsSource and SelectedItem
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedItem="{Binding SelectedObjectType}"
SelectedValue="{Binding SelectedObjectType.ID}"
SelectedValuePath="ID">
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedValue="{Binding SelectedObjectType.ID}"
SelectedValuePath="ID">
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedItem="{Binding SelectedObjectType}"
SelectedValuePath="ID">
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedItem="{Binding SelectedObjectType}">
What do I have to do to make the ComboBox behave as expected?
It seems that a simple UpdateSourceTrigger attribute was missing on the SelectedObjectType binding in the xaml for the ComboBox, like this
<ComboBox ItemsSource="{Binding AvailableObjectTypes}"
SelectedItem="{Binding SelectedObjectType, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding SelectedObjectType.ID}"
SelectedValuePath="ID">

wpf datagrid automatically expand first group

I have a datagrid with the itemsource bound to a ListCollectionView with one group.
When i fill the collection, i want the first group autmatically viewed as expanded, how to code that in wpf (codebehind or mvvm)?
<DataGrid
ItemsSource="{Binding ResultColl}"
SelectedItem="{Binding Path=SelectedResultItem, Mode=TwoWay}"
SelectionMode="Single" IsReadOnly="True" >
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel>
<TextBox Text="{Binding Items[0].ID}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=ID}"/>
<DataGridTextColumn Binding="{Binding Path=Typ}"/>
<DataGridTextColumn Binding="{Binding Path=Info}"/>
<DataGridTextColumn Binding="{Binding Path=orderDate, StringFormat={}{0:dd-MM-yyyy}}"/>
</DataGrid.Columns>
</DataGrid>
In the mvvm controller:
ListCollectionView tmp = new ListCollectionView(myList);
tmp.GroupDescriptions.Add(new PropertyGroupDescription("ID"));
ResultColl = tmp;
...
ListCollectionView _resultColl;
public ListCollectionView ResultColl
{
get { return _resultColl; }
set { _resultColl = value;
RaisePropertyChanged("ResultColl");
if (value != null && _resultColl.Count > 0)
SelectedResultItem = _resultColl.GetItemAt(0) as ItemResult;
}
}
When executing the code, the datagrid is filled the 1st item is selected but group is collapsed.
Add IsExpanded property to your class and add binding to Expander:
<Expander IsExpanded="{Binding Items[0].IsExpanded}">
Set IsExpanded for first to true
you can try add another bool property to your View Model defaulted to true but switching to false when first time used. And bind IsExpanded property of Expander to this with OneTime mode.
public bool IsExpanded
{
get
{
if (_isExpanded)
{
_isExpanded = false;
return true;
}
return false;
}
}
Xaml would be like that:
<Expander IsExpanded="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Mode=OneTime}">

wpf listbox checkbox combination, really stuck

I am trying to link the checkbox and listview together, and then use the binding method to set the path to the object in order to set the check-box IsChecked status in the listbox.
List<Test1> datas = new List<Test1>();
var data = new Test1 {Key = 1, Value = "Hello", IsSelected= true};
datas.Add(data);
data = new Test1 {Key = 2, Value = "Hello2", IsSelected= false};
datas.Add(data);
What I need to happen is that if the checkbox is checked ( IsSelected is true ) then I need to populate with those values and then when I click and unclick the checkbox in the GUI I need it to also select the proper listeview item so I can get to the tag property.
This code below does not set the checkbox IsChecked.
<ListBox ItemsSource="{Binding}" Name="lstSwimLane" Width="225" Height="125" SelectionChanged="lstSwimLane_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected, Mode=TwoWay}"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked" />
<TextBlock Text="{Binding Path=Value}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What do I need to change in order to set the check box to the value in the object? I even tried INotifyChange etc...
Here is the object as well.
public class Test1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _isChecked;
public int Key { get; set; }
public string Value { get; set; }
public bool IsSelected
{
get { return _isChecked; }
set
{
if(_isChecked != value)
{
_isChecked = value;
OnPropertyChanged("IsSelected");
}
}
}
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
I am new to all this wpf, and I am stumped.
Thanks.
Do you need this to work "three-way"? So setting any of the three properties
ListBoxItem.IsSelected
CheckBox.IsChecked
Item1.IsSelected
will affect both of the other properties? Unfortunately, there is no such Binding in WPF so you're gonna have to do a little extra work.
Update
As pointed out by Robert Rossney, a much better solution for this is to bind
ListBoxItem.IsSelected to Item1.IsSelected
CheckBox.IsChecked to ListBoxItem.IsSelected
Updated Xaml
<ListBox ItemsSource="{Binding}"
Name="lstSwimLane"
SelectionMode="Multiple"
Width="225" Height="125" SelectionChanged="lstSwimLane_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected"
Value="{Binding Path=IsSelected,
Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked"
IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}},
Path=IsSelected}">
</CheckBox>
<TextBlock Text="{Binding Path=Value}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In case anyone is interested, here is the markup for the listbox / combox. It will display horizontal.
Thank you all again for all you help as I greatly appreciated it.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding}"
Name="lstSwimLane"
SelectionMode="Multiple"
Width="auto"
Height="auto"
Background="Transparent"
BorderThickness="0"
SelectionChanged="lstSwimLane_SelectionChanged" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Path=IsChecked, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="3,3,3,3">
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
Checked="CheckBox_Checked"
Unchecked="CheckBox_Unchecked"
VerticalAlignment="Center"
Margin="0,0,4,0" />
<TextBlock Text="{Binding Value}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Resources