Find Index of Item in ItemsControl nested inside a LixtBox.Item - c#

I have an ItemsControl nested inside a ListBox.ItemTemplate. The top ListBox is data-bound to an ObservableCollection. The collection is essentially a Purchase which contains Formulae which in turn contain individual products.
Now, if an individual product inside a formula is clicked, I would like it to be deleted from its formula. So, in the event handler, I should be able to determine the product's position using:
var index = [theItemsControl].ItemContainerGenerator.IndexFromContainer((sender as Button).TemplatedParent);
However, in my event handler, I do not how how to find the containing ItemsControl. I cannot give it a fixed name, since it is itself a part of a ListBox.ItemTemplate, meaning there will be multiple instances.
This is my XAML, stripped of any style-related stuff:
<ListBox x:Name="lbBasketFormulae" ItemsSource="{Binding Path=Purchase.Formulae}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<!-- Formula Title -->
<StackPanel Orientation="Horizontal">
<Label Width="30" Content="{Binding Path=Quantity}"></Label>
<Label Content="{Binding Path=FormulaType, Converter={StaticResource formulaTypeToNameConverter}}"></Label>
</StackPanel>
<!-- Formula Products -->
<ItemsControl ItemsSource="{Binding Path=Products}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="bnBasketFormulaProduct" HorizontalContentAlignment="Left" Content="{Binding Path=Name}" Click="bnBasketFormulaProduct_Click">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock Text="{TemplateBinding Content}" />
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So, my question is: How do I find the position of my product inside my formula and the position of that formula inside the purchase, so that I can remove it from the ObservableCollection? (Changing the collection should then automatically reflect to the UI since it is data-bound.)
Many thanks in advance for any advice or hints!
Regards,
Chris

It is true that you should be able to do it via the viewmodel. But if you want you could use:
VisualTreeHelper.GetParent(myUserControl);

The answer is you don't find any positions of anything using ItemContainerGenerator.IndexFromContainer. Your problem is clearly taking place inside ViewModel and therefore you should seek for selected item or whatever inside your ViewModel and not in ListBox or code behind of Window.
Therefore I suggest you to create a proper ViewModel with proper Bindings.

Related

Remove item from itemControls

I'm a beginner in wpf and I'like to know the best practices for handling crud operation on a list a user control.
As the example below, I have create a list of individual and each of them are binding in a user control (mvvm...).
After several search, I have find possibility to uses a 'specific' binding with RelativeSource,FindAncestors etc...
But it seems to me very ugly because, it breaks the principle of inversion of dependency. How to be agnostic of the parent or how to bind from the parent an event/command for delete an item from a list.
Here's the main list
<ItemsControl ItemsSource="{Binding Path=Items, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<components:Individual Content="{Binding }" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And here's the definition of the UserControl
<UserControl:Indivudual>
...
<TextBox Name="Text" Text="{Binding Path=Name, Mode=TwoWay}" Grid.Row="0"/>
<Button Grid.Row="0" Grid.Column="2">Delete</Button>
</UserControl>

XAML Element Alignment issue

I have a list view that will contain notes that I input. I am having trouble figuring out how to have the list view item look how I want it to.
Below is how it should look:
And this is what it currently looks like:
How do I write the list view item in XAML so that the Date and time appear to the very top-right of each list view item, with the text of the note to the left?
<ListView x:Name="list" ItemsSource="{Binding Note}" BorderBrush="{x:Null}" BorderThickness="0">
<DataTemplate>
<ListViewItem>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ListViewItem>
</DataTemplate>
</ListView>
Any help at all is much appreciated!
You are missing a number of elements required in order to get your screen to look the way you want.
You need to define the ItemTemplate for the ListView. You're on the right track here, it is a DataTemplate declared in XAML, you just have to apply it to the ListView.ItemTemplate property.
You need to set the HorizontalContentAlignment of the ListView to Stretch (the default is Left, which means your items will not fill the entire content area).
You need to use a DockPanel (or other similar panel) inside your DataTemplate to place your date content on the right, and the remainder of your content on the left.
You need to disable Horizontal Scrolling (ScrollViewer.HorizontalScrollBarVisbility) on the ListView in order to make your content wrap (otherwise it will just happily draw it all on one line).
I've included a sample ListView that should get you started.
<ListView
ItemsSource="{Binding Items}"
HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock
TextWrapping="Wrap"
Text="{Binding Date}"
Background="Magenta"
DockPanel.Dock="Right" />
<TextBlock Text="{Binding Content}" Background="Lime" />
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

WPF, Data Binding, Lookup hierarchy

I am new to WPF, and trying to develop a small application using DataBinding following the MVVM paradigm.
I am trying to provide a binding functionality to the ObservableCollection of Documents (my type). The First Label would display a Documents path (available through Attribute property), while the next children - Pages of the Documents - would display appropriate information: page index and page content (an image).
Here is an issue - how can I create a lookup binding to a parent Label? On Button Click command I would like to pass the documents path, which was available earlier in the first DataTemplate.
Is there a way to tackle this issue?
How would you recommend going around it?
Also, is there a better way to tackle "nested" structures (collections within collections)?
Here is the code https://gist.github.com/b5760982ba81e8ee4036, line 14
you should use RelativeSource:
<ItemsControl ItemsSource="{Binding Documents}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Path=Attribute.Path}"/>
<ItemsControl ItemsSource="{Binding Pages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Index}"/>
<Button Content="{Binding Content}"
Command="{x:Static viewModel:DocViewModel.Tests }"
CommandParameter="{Binding Path=DataContext.Attribute.Path,RelativeSource={RelativeSource AncestorType=ContentPresenter, Mode=FindAncestor,AncestorLevel=2"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

Add more of my usercontrol container or usercontrol collection display

I do not know what the container/control im looking for would be called, so I cannot really search for it.
Add More of Same Usercontrol Usercontrol
Clicking on + would add a new instance of My Usercontrol to the right of the existing ones
Clicking on X would dispose the usercontrol that was clicked
I'm not really looking for a tab control that would put each new instance on a new tab, but if there is nothing else then it might do.
The design is not to be as shown in the image obviously, the image just illustrates the basic idea
Any keyword/name suggestions or links to existing implementations?
e.g. Maybe there is a style that turns a ListBox into something suitable?
I would use an ItemsControl and customize it's ItemsPanelTemplate to be whatever you want.
ItemsControls are meant for iterating through a collection of objects, and displaying them in whatever form you want. I wrote some simple code samples of them here if you're interested, or here's another quick example:
<DockPanel x:Name="RootPanel">
<Button Style="{StaticResource AddButtonStyle}"
DockPanel.Dock="Right" VerticalAlignment="Center"
Command="{Binding AddItemCommand" />
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<local:MyUserControl />
<Button Style="{StaticResource RemoveButtonStyle}"
Command="{Binding ElementName=RootPanel, Path=DataContext.RemoveItemCommand}"
CommandParameter="{Binding }"
HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
Your ItemsControl would be bound to an ObservableCollection of objects, and your Add/Remove buttons would simply add/remove items from that collection. Since it is an ObservableCollection, it will notify the UI when the collection gets changed and automatically update.
You can indeed use a ListBox and set its ItemTemplate and ItemsPanelTemplate:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Of course, your ItemTemplate would be a reference to your control.
You could look at something called a carousel control which uses a list of objects behind it and displays them similarly to itunes. This could be a bit over the top but is one solution. An example can be seen here
If this is too advanced for your needs, could it be as simple as a stackpanel with a scrollbar which is bound to a list of your user controls?

Showing a dynamic size list in XAML (readonly)

I want to show a list of "properties" in my application. A property is simply a name/value pair. The number of properties is dynamic.
The best way to do this? The only thing I can come up with is creating a ListView with an ItemTemplate. But then the items are selectable, and that's not what I want. If I make the list read-only, it becomes gray. Don't like that either.
Anyone has a better suggestion?
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Properties}">
<ItemsControl.ItemTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Use a Grid for ItemsControl.ItemsPanel with SharedSizeGroup if you want all items to line up nicely.
Look here:
http://www.codeplex.com/wpg or here
http://dvuyka.spaces.live.com/blog/cns!305B02907E9BE19A!448.entry
They are both implmentations of PropertyGrid from WinForms

Categories

Resources