How to i add an Item Click event to an items control - c#

I am having problems with generating a click event for items inside an items control. I am new to xaml nad wpf. Can you the experts help me out. Below is the code that i have come up with but now having no clue on how to add a click event to for the generated items. Will very much appreciate your responses. Thank you for reading
<ItemsControl ItemsSource="{Binding Text, Source={StaticResource TextContainer}}">
<!--text is an object bein made public from TextToDisplay. There can be many objects released ratger than one in this case-->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ItemWidth="100"
ItemHeight="100" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type sys:String}">
<Border CornerRadius="100"
Background="BlueViolet">
<Button Margin="20"
Content="{Binding}"
HorizontalContentAlignment="Center" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

probably the easiest thing you can do is create your own user control... make it a custom button and add click event to that control so everytime the listbox add your control it will already have a click_event built in.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
// add your code here.
}
then for the listbox do something like that...
private void AddItemsButton_Click(object sender, RoutedEventArgs e)
{
ListBoxTest.Items.Add(new UserControl1());
}
this adds a usercontrol button to the listbox everytime you click on a button titled "add items"

Related

XAML binding to IsChecked for all ToggleButtons in an ItemsControl

I have seen many questions similar to mine but none that solves or addresses my problem.
What I have is a group of toggle buttons that exist inside of an ItemsControl, and these toggle buttons are created dynamically at run time based off of the number of people inside of an index that the ItemSource of the ItemsControl is bound to. When these toggle buttons are clicked in the UI, some filtering is done based on the person's name. Multiple buttons or even all the buttons can be selected if so desired. There is also a "clear" button which simply removes all filtering and should reset the toggle button IsClicked states.
My problem is that when I click the clear button, all of the toggle buttons that were clicked remain clicked. I am trying to have the clear button reset every ToggleButton's IsClicked value to false by binding the IsClicked value to a property that is managed in the code, but no matter what I try I cannot get this to work.
Code:
Xaml
<Button Content="Clear Filter" HorizontalAlignment="Center" Margin="0,0,0,1" VerticalAlignment="Bottom" Grid.Column="1" Click="ClearClick"/>
<ItemsControl ItemsSource="{Binding Source={StaticResource peopleSorted}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Name="toggleButton" Margin="0,0,5,0" Command="ApplicationCommands.Open"
CommandParameter="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
c# ViewModel:
private void ClearClick(object sender, RoutedEventArgs e)
{
this.m_viewModel.ClearFiltering();
}
C# model:
public bool IsChecked
{
get
{
return this.m_isChecked;
}
set
{
this.m_isChecked = value;
this.OnPropertyChanged("IsChecked");
}
}private bool m_isChecked;
public void ClearFiltering()
{
m_hashTable.Clear();
this.IsChecked = false;
}
I am pretty stuck. I feel like the reason the binding isn't working is that the toggle buttons are dynamically created inside of an ItemsControl, but I am not sure if that's what's wrong or how to fix it if it is.
UPDATE
I was able to work around this by doing a swap and swap-back on the data of observable collection that the ToggleButtons ItemsControl is bound to, which triggered the OnPropertyChanged for the entire collection of toggle buttons, thus resetting that part of the UI. It is a simple hack with almost no overhead and four lines of code, but doesn't really answer the original question.

ListView SelectItem Binding not working as expected

I have a fairly straight forward listview control for my Windows 8 XAML/C# application. I am binding the listview to a PersonList and that works correctly. However, what I'd like to do and haven't been able to find the answer for is I want the to click an item in the listview and be able to display the PersonSingle object to the other textboxes on the screen.
I've read some posts that indicate that the listview may not be the right control for this operation. Am I missing something in my listview that would allow me to do this operation or should I use a different control?
<ListView
x:Name="itemListView"
Visibility="Visible"
Width="auto"
Height="auto"
ItemsSource="{Binding PersonList, Mode=TwoWay}"
SelectedItem = "{Binding PersonSingle, Mode=OneWay}"
ItemTemplate="{StaticResource person80Template}"
SelectionMode="Single"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Stretch">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="7,7,0,0">
<Button
AutomationProperties.Name="PersonValue"
Content="{Binding PersonName}"
Style="{StaticResource TextButtonStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
UPDATE:
So I figured out how to do it in a non-MVVM way (or at least not in a true MVVM way)
I added an ItemClick event to my ListView:
ItemClick="itemListView_ItemClick"
And then in the code behind I added the following:
private void itemListView_ItemClick(object sender, ItemClickEventArgs e)
{
VM.PersonSingle = ((Person)e.ClickedItem);
}
That works, but like I said, it doesn't feel very MVVM'ish. If you have any suggestions on how to make it work without having to manually set the PersonSingle object please answer below.
Your ItemClick solution is the right solution. You could create an attached behavior if you are opposed to handling events, but that's your choice.

Finding what's selected in HubSection GridView DataTemplate

I have the following code that makes up a HubSection within a Hub.
<HubSection DataContext="{Binding Path=[0], Source={StaticResource groupedItemsViewSource}}" Padding="40,30,40,0">
<HubSection.Background>
<ImageBrush ImageSource="Images/BG.jpg" Stretch="UniformToFill" />
</HubSection.Background>
<HubSection.Header>
<TextBlock x:Uid="Section1Header" TextLineBounds="TrimToBaseline" OpticalMarginAlignment="TrimSideBearings" Text="English"/>
</HubSection.Header>
<DataTemplate>
<GridView
x:Name="itemGridView1"
Margin="-4,-4,0,0"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource Standard240x320ItemTemplate}"
SelectionMode="Single"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
</GridView>
</DataTemplate>
</HubSection>
I have an AppBar set up as well, but I'm not sure how to tell the AppBar what is selected in the HubSection.
Please advise.
Edit: To clarify, I'm facing issues with implementing code such as itemGridView1.selectedItem because I'm being told it "does not exist in the current context".
Most of the advice regarding this issue centres on iterating through the visual tree of your Frame, but that doesn't seem to work well in the XAML Hub Section.
Instead, implement a SelectionChanged event in your GridView. When this is triggered, it will send details of the GridView sender, which can then be referenced for additional information such as .SelectedItem.
private void GridViewName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var GridState = sender as GridView;
if(GridState.SelectedItems.Count>0)
{
// Do something
}
}

How do I get access to the item in a ListBox that is being rendered rather than its source data?

In a continuation from my question here
I tried using the solution provided in the linked answer, however when I give it the image which the ListBox is binding to, it gives me the wrong position, because the Item Template is loading in a source URL rather than the actual image, and it seems the data is null.
My Item Template looks like this:
<ListBox ItemsSource="{Binding Items}"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
Height="64" Name="listBoxSource"
VerticalAlignment="Bottom"
SelectionChanged="listBoxSource_SelectionChanged" Canvas.Left="32" Canvas.Top="365" Width="596"
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="ListImage" Source="{Binding thumbnailURL}" Height="64" Width="64"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
How do I get access to "ListImage" for the currently selected Item?
Every ItemsControl has an ItemsContainerGenerator, which (surprisingly enough) is responsible for generating a control for each item in the list. It provides a few useful methods for finding the container of a given item, and vice versa. You can use it like this:
private void listBoxSource_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBox) sender;
var containerGenerator = listBox.ItemContainerGenerator;
var container = (UIElement)containerGenerator.ContainerFromItem(listBox.SelectedItem);
}
You can then use the variable container with the solution from your other post to find the coordinates,
Point position = container.GetRelativePosition(Application.Current.RootVisual);
And on a side note, in your DataTemplate you don't need the StackPanel, since the ListBox is providing that with its ItemsPanelTemplate.
<DataTemplate>
<Image x:Name="ListImage" Source="{Binding thumbnailURL}" Height="64" Width="64"/>
</DataTemplate>
on tap event you can do this:
private void image_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Image selectedImage = e.OriginalSource as Image;
}
is this what you need?
I would suggest a different solution because the way you are trying to solve it (finding the control) is prone to error.
Make the DataTemplate a resource and refer to it in the ListBox by using ItemTemplate="{StaticResource myTemplate}"
Next, when an item is selected, add a ContentControl to the Canvas, set its ContentTemplate to the same DataTemplate and the DataContext to the SelectedItem.
This way you only have to define the template once (one place to maintain it) and do not have to walk the VisualTree.

Add adorner to bound children?

<ItemsControl Name="CanvasTableMap" ItemsSource="{Binding}" ItemsPanel="{DynamicResource ItemsPanelTemplate1}" ItemTemplate="{DynamicResource DataTemplate1}">
<ItemsControl.Resources>
<ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
<WrapPanel Background="{DynamicResource ContentBackground}" />
</ItemsPanelTemplate>
<DataTemplate x:Key="DataTemplate1">
<Button Canvas.Left="100" Content="{Binding Name}" Template="{DynamicResource ButtonTableTemplate}"></Button>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Here is my code.No problem with that. I have created an adorner and i would like to add an adorner for each button when i want. It is a little difficult as i dont know how to get the Buttons. CanvasTableMap.Items returns the Model so i dont know how to get access to the controls efficiently.
An easy way to do that is to define a handler for the Loaded event of the button, and add the adorner in that handler:
XAML
<Button Canvas.Left="100" Content="{Binding Name}" ... Loaded="Button_Loaded" />
Code-behind
private void Button_Loaded(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var layer = AdornerLayer.GetAdornerLayer(button);
// Add the adorner
...
}
If you don't want to use code-behind, you can create an attached behavior (either with System.Windows.Interactivity or by creating an attached property)
You can use the ItemContainerGenerator to get the control created from the data (ContainerFromItem). Usually doing things that way is not such a good idea though.

Categories