Consider the following XAML
<ItemsControl ItemsSource="{Binding Path=MyItems, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" AlternationCount="999" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex),
RelativeSource={RelativeSource TemplatedParent},
FallbackValue=FAIL,
StringFormat={}Index is {0}}" />
<ItemsControl ItemsSource="{Binding Path=MySubItems, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}, AncestorLevel=1}, Path=(ItemsControl.AlternationIndex)}"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}, AncestorLevel=2}, Path=(ItemsControl.AlternationIndex)}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
There are three TextBlock nodes. The 1st TextBlock is a direct child of the 1st ItemsControl, and shows the AlternationIndex, as expected. However, I need that AlternationIndex a level deeper, in the second ItemsControl. Therefore I can't use TemplatedParent and thought I could find the Ancestor with AncestorLevel. However, both TextBlock nodes in the 2nd ItemsControl show "0".
What I'm I missing? How do I target the 1st ItemsControl from within the 2nd ItemsControl?
The AlternationIndex won't be on the ItemsControl but on each of its children. Using DataTemplate your ItemsControl will store each children in a ContentPresenter which will have the AlternationIndex. What you need to modify:
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}, AncestorLevel=2}, Path=(ItemsControl.AlternationIndex)}"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}, AncestorLevel=2}, Path=(ItemsControl.AlternationIndex)}"/>
Related
I've got a WPF Combobox with about 1000 rows.
Each Row has a checkbox to allow selecting mulltiple rows.
If nothing has been selected it opens just fine. Howeve if I've already selected something and now want to change my selection it takes about 30s for the ComboBox to open and it has for some reason scrolled to the bottom.
I'm using VirtualizingStackPanel but it doesn't seem to fix the problem.
<ComboBox
x:Name="cbStockCat"
Grid.Column="1"
Margin="2,0,2,0"
Padding="2,10,0,4"
materialDesign:HintAssist.Hint="Stock Category"
materialDesign:HintAssist.IsFloating="True"
StaysOpenOnEdit="True"
customProperties:EnterKeyTraversalExtension.IsEnabled="True"
AllowDrop="True"
IsEditable="True"
ToolTip="{Binding StockCategoryCollection.ToolTipText}"
TabIndex="{Binding StockCatTabIndex, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding StockCategoryCollection.Text, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding StockCategoryCollection}"
Cursor="Hand">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>
<DataTemplate >
<CheckBox
IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Content="{Binding}"
Background="{StaticResource BrushPrimaryLighter}"
CommandParameter="{Binding}" >
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Any ideas?
My Application consists of a MainWindow with a ContentControl and I change the ViewModel depending on the selected menu.
One of the UserControls I display as content contains the following WrapPanel:
<UserControl ...>
<Grid>
<WrapPanel>
<ItemsControl ItemsSource="{Binding Connections}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.ConnectionSelectCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
FocusManager.FocusedElement="{Binding ElementName=InstanceName}"
Style="{DynamicResource DashboardButton}">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" Text="{Binding Name}" />
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete"
Command="{Binding ConnectionRemoveCommand}"
CommandParameter="{Binding}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</WrapPanel>
</Grid>
</UserControl>
The Command on the ContextMenu doesn't work because it tries to call ConnectionRemoveCommand on the Connection object instead of the ConnectionViewModel which is the DataContext of the UserControl.
How do I bind the Command to the ConnectionViewModel with the CommandParameter being the Connection object?
If you bind the Tag property of the Button to the DataContext of the ItemsControl, you could then bind to it using the PlacementTarget of the ContextMenu:
<Button Command="{Binding DataContext.ConnectionSelectCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
FocusManager.FocusedElement="{Binding ElementName=InstanceName}"
Style="{DynamicResource DashboardButton}"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" Text="{Binding Name}" />
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete"
Command="{Binding PlacementTarget.Tag.ConnectionRemoveCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
I am trying to bind the background color of a TextBox and use a converter. However, I can't figure out the correct binding due to the TextBox being in a DataTemplate and in a ContentControl.
The DebuggingConverter doesn't fire unless I set the binding path from Path=StateColor to Path=.
Here is the xaml :
<GridViewColumn Header="Value" Width="{Binding SelectedDeviceCol2, Source={x:Static properties:Settings.Default}, Mode=TwoWay}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding Path=Value, Mode=TwoWay}" IsEnabled="{Binding Path=ReadOnly, Converter={StaticResource readOnlyToEnabledConverter}}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:VMDeviceCommand}">
<Button Content="{Binding Name}" Height="24" IsEnabled="True" Click="Button_Click_GetObjectProperty"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:DateTime}">
<DatePicker SelectedDate="{Binding Path=.}"
SelectedDateFormat="Short"
FirstDayOfWeek="Monday"
IsTodayHighlighted="True" >
</DatePicker>
</DataTemplate>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=.}" TextChanged="TextBox_OnTextChanged">
<TextBox.Background>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=StateColor, Converter={StaticResource DebuggingConverter}}"/>
</TextBox.Background>
</TextBox>
</DataTemplate>
<DataTemplate DataType="{x:Type System:UInt16}">
<xctk:IntegerUpDown Text="{Binding Path=.}" ValueChanged="UpDownBase_OnValueChanged" >
</xctk:IntegerUpDown>
</DataTemplate>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=.}" Click="CheckBox_Click"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
ContentControl doesn't have a StateColor property, so the Binding never gets its value and never has anything to pass to a converter.
If the ContentControl's DataContext has a StateColor property, that's easy:
<SolidColorBrush
Color="{Binding DataContext.StateColor, RelativeSource={RelativeSource AncestorType=ContentControl}, Converter={StaticResource DebuggingConverter}}"
/>
Hi i'm creating an checklistbox
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="CheckBox" Content="{Binding Path=Info.Name}" IsChecked="{Binding IsChecked,Mode=TwoWay}" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainViewModel}}, Path=SimpleCommand}">
</CheckBox>
<TextBlock Margin="20,0,0,0" Text="{Binding Path=Status}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
but when i check the simplecommand isn't call
SimpleCommand = new RelayCommand(obj => MessageBox.Show("alert"), obj => true);
Use the control name rather than the viewmodel for ancestor type
<CheckBox x:Name="CheckBox"
Content="{Binding Path=Info.Name}"
IsChecked="{Binding IsChecked,Mode=TwoWay}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=SimpleCommand}"/>
This is my code of ContentPresenter:
<ListBox ItemsSource="{Binding Items}" BorderThickness="0" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter x:Name="PART_ValueContainer">
<ContentPresenter.Content>
<MultiBinding>
<Binding Path="Value"/>
<Binding Path="ReadOnly"/>
</MultiBinding>
</ContentPresenter.Content>
<ContentPresenter.Resources>
<DataTemplate>
<TextBox IsReadOnly="{Binding Path=Content.ReadOnly, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
Text="{Binding Path=Content.Value, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}"
TextAlignment="Left"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I trying to fill the Text from object Items.Value and property IsReadOnly from Items.ReadOnly.
It doesn't work, I know that is not good solution, but, how to make something like that?