WPF - Binding a ComboBoxItem visibility using BooleanToVisibilityConverter - wpf

I have a Datagrid, with a column that has a combobox in its header. I want to control the visibility of items in the combobox based on the value of a certain flag.
This is how my XAML looks:
<DataGrid x:Name="Table1" Height="{Binding ElementName=ElasticOne1,Path=ActualHeight}" Width="{Binding ElementName=ElasticOne1,Path=ActualWidth}" Padding="5,5,5,5" IsReadOnly="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionMode="Single" >
<DataGrid.Columns>
<DataGridTextColumn x:Name="Column2" Header="Source" Width="80">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Margin="0">
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</StackPanel.Resources>
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" Margin="5"/>
<ComboBox HorizontalAlignment="Stretch" Margin="0" >
<ComboBoxItem Tag="0" IsSelected="True">All</ComboBoxItem>
<ComboBoxItem Visibility="{Binding ShowCopybookInSourceCombobox, Converter={StaticResource BoolToVis}}">Copybook</ComboBoxItem>
<ComboBoxItem>Prototype</ComboBoxItem>
</ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
And this is the declaration of the flag in code:
Public ReadOnly Property ShowCopybookInSourceCombobox As Boolean
Get
Return myFlag1 Or myFlag2
End Get
End Property
No matter what the value of my flag, the combobox item is always showing. I haven't seen any examples so far of binding the visibility of a comboboxitem this way. Am I on the wrong path?
Thanks for all your input.
Edit: BooleanToVisibilityConverter is a built-in class that I am using - https://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter(v=vs.110).aspx

Related

WPF: How to Set the Width of a ComboBox's DropDown Correctly

I'm about to design a DropDown in WPF using XAML. If my text gets longer than the Width my DropDown element of the ComboBox is larger than the TextBox (as shown by the red arrow). Texts beeing to long are handled by an elllipsis (...).
Any ideas how to correct this?
This is my current XAML code:
<ItemsControl x:Name="ItemsControl"
ItemsSource="{Binding FilterUiModels}">
<ItemsControl.ItemTemplate>
<DataTemplate x:Name="UiModelTemplate">
<ComboBox x:Name="FilterComboBox"
ItemsSource="{Binding AvailableItems}"
SelectedItem="{Binding FilterItem}"
ScrollViewer.CanContentScroll="False"
Width="200">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Width="{Binding ActualWidth, ElementName=FilterComboBox}"
Text="{Binding}"
TextTrimming="CharacterEllipsis">
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Bind the Width of the Popup to the Width of the ComboBox and set the ScrollViewer.HorizontalScrollBarVisibility attached property to false to hide any horizontal scrollbar:
<ComboBox x:Name="FilterComboBox"
ItemsSource="{StaticResource localTimeList}"
SelectedItem="{Binding FilterItem}"
ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Width="200">
<ComboBox.Resources>
<Style TargetType="Popup">
<Setter Property="Width" Value="{Binding ActualWidth, ElementName=FilterComboBox}"/>
</Style>
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Width="{Binding ActualWidth, ElementName=FilterComboBox}"
Text="{Binding}"
TextTrimming="CharacterEllipsis">
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Binding textboxes inside a usercontrol to datagrid

Is the way that I'm binding the UserControl to the DataGrid correct?
In my MainWindow I have a datagrid (code below):
<DataGrid x:Name="MusicListGrid" ItemsSource="{Binding MusicList}" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Artist" Binding="{Binding Artist,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Album" Binding="{Binding Album,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Track" Binding="{Binding Track,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>
The usercontrol inside my MainWindow, that I'm binding to the selected item of the datagrid:
DataTemplate(in MainWindow):
<Window.Resources>
<DataTemplate x:Key="MusicDetailListTemplate" >
<v:MusicDetailView DataContext="{Binding ElementName=MusicListGrid,Path=SelectedItem}" />
</DataTemplate>
</Window.Resources>
ContentControl(in MainWindow):
<ContentControl x:Name="musicDetail" Content="{Binding}" ContentTemplate="{StaticResource MusicDetailListTemplate}" Grid.Column="1" />
The textboxes inside my UserControl looks like this:
<TextBox Grid.Column="1" Grid.Row="0" Width="200" Margin="10,5" Text="{Binding Artist,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Grid.Row="1" Width="200" Margin="10,5" Text="{Binding Album,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Grid.Row="2" Width="200" Margin="10,5" Text="{Binding Track,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
This works, but I'm not sure if I'm doing the correct way?
Can I also bind a textbox to the datagrid like this:
<TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Path=MusicListGrid.Artist.SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
The data in the datagrid is an ObservableCollection<Music> (music is my model).
If I replace my UserControl with a tabcontrol, should I have the tabcontrol be a separate view or just be part of MainWindow? And have the content of the tabcontrol be separate views? I was thinking of having the datagrid and a tabcontrol with 2 tabs, one for editing and the other for displaying (to look more presentable).
Sorry if these are very basic questions, I just want to be on the right path.
It is more common to set the Content property of the ContentControl element to the data object:
<ContentControl x:Name="musicDetail" Content="{Binding ElementName=MusicListGrid,
Path=SelectedItem}" ContentTemplate="{StaticResource MusicDetailListTemplate}" />
The DataContext defines what the data of the relevant type should look like in the UI, so you shouldn't really set the DataContext there... it is automatically set to the relevant data object instance... it should look more like this (where Prefix is the XML Namespace Prefix that you set up for your project and YourClass is the type of object in the DataGrid):
<Window.Resources>
<DataTemplate x:Key="MusicDetailListTemplate" DataType="{x:Type Prefix:YourClass}">
<v:MusicDetailView DataContext="{Binding}" />
</DataTemplate>
</Window.Resources>

how to bind the selected item from the combobox to textblock inside datagrid

I am having combobox inside datagrid which is inside cell editing template.
What i want is that when a user select an item from the combobox and move to the next cell, the selected item must bind to the textblock of that same cell.
if anyone knows how to do help me. here is my xaml
<DataGrid AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="False"
Grid.Row="1" Grid.ColumnSpan="7" Name="attendancegrid" Background="#FFDCE8EB" CanUserAddRows="False"
BorderBrush="Chocolate" BorderThickness="5" RowHeight="30" IsSynchronizedWithCurrentItem="True"
HorizontalGridLinesBrush="#FFB74646" IsReadOnly="False" Foreground="Black" Loaded="attendancegrid_Loaded"
SelectionChanged="attendancegrid_SelectionChanged" CurrentCellChanged="attendancegrid_CurrentCellChanged"
CellEditEnding="attendancegrid_CellEditEnding">
<DataGridTemplateColumn Header="Monday" Width="100">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="monday" Width="50" IsSynchronizedWithCurrentItem="true" Loaded="monday_Loaded" SelectionChanged="monday_SelectionChanged"></ComboBox>
<ComboBox x:Name="staff" Width="50" Loaded="staff_Loaded"></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<TextBlock x:Name="mon"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
You have to create one collection property to be bound on Combobox like
public List<string> MyCollection{get;set;}
and one string property for binding it to the SelectedItem of ComboBox and Your TextBlock like
private string _SelectedCollectionItem;
public string SelectedCollectionItem
{
get{return _SelectedCollectionItem;}
set{_SelectedCollectionItem=value;
RaisePropertyChanged("SelectedCollectionItem");}
}
now in your xaml do like this
DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding MyCollection}" SelectedItem={Binding SelectedCollectionItem,Mode=TwoWay}></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<TextBlock Text={Binding SelectedCollectionItem}></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>

WPF DataGrid Element Name of other DataGridTemplateColumn

I have two Datagrid Template column.
1) Fist column is a Combobox
2) Second column with Extended IntergerUpDown control
I need to set the IntegerUpDown Maximum value based on the Combox box SelectedItem value.
Please help me how to accomplish this. Sample xaml below.
<Grid><DataGrid ItemsSource="{Binding List1}" Name="x1">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ColorTemplate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.List2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name" SelectedValue="{Binding ColourId}" SelectedValuePath="Id" Tag="{Binding Id}"
HorizontalAlignment="Stretch" x:Name="discussTemplate" VerticalAlignment="Stretch"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="UPDown" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<extToolkit:IntegerUpDown AllowSpin="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Minimum="0"
x:Name="updown"
Maximum="{Binding ???}" >
</extToolkit:IntegerUpDown>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
simply bind to the value of your itemsrow? so if ColourID is the property of your itemsrow which is set by your combobox. you can bind your Maximum to ColourID
<extToolkit:IntegerUpDown AllowSpin="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Minimum="0"
Maximum="{Binding ColourId}" >
</extToolkit:IntegerUpDown>

Silverlight: DataGrid inside ListBox. Binding on DataGrid Column to a parent listbox's ItemsSource property. Silverlight

I'm a little puzzled with this one. I have a Collection called "AllProducts", which has a collection inside called "ProductGroups" (to group items separately) which inside contain a collection of "Product" objects called "LineItems" (the actual items).
To set this up, I have set a ListBox with a DataGrid inside the itemtemplate for the ListBox's Items. Setting the ItemsSource of the listbox to "ProductGroups" and the DataGrid(In the itemtemplate) has an ItemsSource pointing to LineItems.
The DataGrid contains Columns:
"Select" -- A checkbox and a radiobutton
"Image" -- string
"Name" -- string
"Description" -- string
"Price" -- string
The "ProductGroup" collection has a bool property called "IsListItem" per group, which is supposed to tell me if you can select multiple or a single item for that group (hence the checkbox and radiobutton in the first column of the DataGrid). I want the checkbuttons and radiobuttons visibility property to be bound to "IsListItem" bool which I have already set up with a BoolToVisibility converter with an "IsInverted" property to switch them back and forth.
The problem that I'm running into is that I want the first column of the DataGrid which contains the checkboxes/radiobuttons to be bound to the IsLineItem of ProductGroups (which is the ListBox's ItemsSource. But Since the DataGrid's ItemsSource is bound to LineItems, the DataContext of the DataGrid is set to LineItems and I can't access anything outside of it.
Here's some code to help:
ListBox XAML:
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<StackPanel Canvas.Left="20" Canvas.Top="20" Width="520" Height="360">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</Canvas>
</sdk:TabItem>
ListBox ItemTemplate XAML:
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</DataTemplate>
And my Objects:
public class AllProducts
{
public IEnumerable<ProductOptionGroup> ProductGroups;
}
public class ProductOptionGroup
{
public string GroupName;
public IEnumerable<Product> LineItems;
public bool IsListType;
}
public class Product
{
public int ID;
public int OrdinalNumber;
public string Name;
public string Description;
public Decimal Price;
public string ImageUrl;
public CartItemType Type;
}
(MichaelS): I tried setting it to the Parent "PaymentRoot" Canvas' DataContext but it isn't doing anything for me. Here is what I tried:
<CheckBox Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=PaymentRoot, Path=DataContext.GroupName}"/>
(MichaelS): here's how it's set up in my VM:
private AllProducts products;
public AllProducts Products
{
get
{
return products;
}
set
{
//Products.ProductGroups[0].LineItems[0].
products = value;
RaisePropertyChanged("Products");
}
}
Update:
The below code won't work since it's a known issue that was discovered late in the Silverlight 3 timeframe.
Setting the Binding in the LoadingRow event using column.GetCellContent(e.Row) should solve the issue.
In this particular case , you want be able to do that since the dataGrid itself is a dataTemplate of another control.
Try this:
Wrap your datagrid with another Grid. Name it, and use it for the element binding.
This code should work:
<StackPanel>
<Grid x:Name="GridDataHolder">
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</StackPanel>
By the way, i'm not sure if binding works with public members, you may need to change those binded members to public properties.
Finally got it fixed! What I had to end up doing was getting rid of the DataGrid altogether because a lot of controls from the toolkit seem to have that bug not being able to bind outside even through Element Binding.
I turned the DataGrid into a ListBox with another DataTemplate for the LineItems completely customizing the look of it to achieve a similar look that I had with the DataGrid.
Also to note: I tried at first binding to the StackPanel outside of the DataTemplate through Element Binding but it seemed to have a problem with that. So I set the grid inside the DataTemplate's DataContext and then I made the checkbox and radiobutton bound to the grid inside the Parent Listbox's dataTemplate through element binding and that did the trick!
Here is some working code for anybody who runs into this same issue later on!:
<DataTemplate x:Key="LineItemsTemplate">
<StackPanel Orientation="Horizontal">
<StackPanel Height="100" Width="100">
<StackPanel Height="40" Orientation="Vertical">
<RadioButton Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
<CheckBox Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}"/>
</StackPanel>
<Image Source="{Binding ImageUrl}" Height="50" />
</StackPanel>
<TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ProductListItem">
<StackPanel x:Name="GridDataHolder">
<TextBlock TextWrapping="Wrap" Text="{Binding GroupName}" VerticalAlignment="Top" d:LayoutOverrides="Width"/>
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding LineItems}" ItemTemplate="{StaticResource LineItemsTemplate}">
</ListBox>
</StackPanel>
</DataTemplate>
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas>
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<ScrollViewer Height="389" Width="545" x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<StackPanel Orientation="Vertical" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="500" HorizontalAlignment="Center">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</ScrollViewer>
</Canvas>
</sdk:TabItem>
Thanks MichaelS for all your help! You got me going the right way!

Resources