I have a window with a property called IpList of type ObervableCollection<string> and I set the window's DataContext property to the window itself so that I can bind properties from XAML elements to properties of the window. One XAML element in my window is a ListBox that has an ItemTemplate:
<ListBox
ItemsSource="{Binding IpList}"
x:Name="lbIps">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Button
Click="lbIps_bnClose_Click"
Content="X"
DockPanel.Dock="Left" />
<TextBlock
Text="{Binding}" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want the list box items to remove themselves when their "X" button is clicked. My first attempt was to obtain the selected item index and remove this from the list. But when I only click on the button, no item is selected. My second attempt was to remove the item by value instead of index, but I couldn't figure out how to obtain the value of the list box item containing the clicked button. So my questions are: Is there a possibility to obtain the index/value of the list box item containing the clicked button? If so, how can I do this? Is there another way to remove the parent list box item of a clicked "X" button?
private void lbIps_bnClose_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as [yourViewModelName];
var button = sender as Button;
var item = (string)button.DataContext;
vm.IpList.Remove(item);
}
If you're not using MVVM:
Put this in the click event
string s=(string)((sender as Button).DataContext);
IpList.Remove(item);
Related
I'm currently making a transferring data from one listbox to another.
With WPF I have:
<Grid>
<ListBox Margin="10,29,194,301" Name="LeftListBox"/>
<ListBox Margin="0,29,16,301" Name="RightListBox" HorizontalAlignment="Right" Width="173" />
<Button Name="AddButton" Height="23" Margin="34,135,227,0" VerticalAlignment="Top"
Click="AddButton_Click">Add >></Button>
<Button Name="RemoveButton" Margin="227,135,34,264"
Click="RemoveButton_Click"><< Remove</Button>
</Grid>
For my C# code, I created two methods that loads the left box's elements by using an array of Strings and the right one's.
Now My issue is that I want an element of the left box to be placed into the right box after the last element of the right box's list. So when I click on add, it should execute this method:
private void AddButton_Click(object sender, RoutedEventArgs e)
{
// Find the right item and it's value and index
currentItemText = LeftListBox.SelectedValue.ToString();
currentItemIndex = LeftListBox.SelectedIndex;
ObservableCollection<string> oList;
oList = new System.Collections.ObjectModel.ObservableCollection<string>(toRemoveList);
RightListBox.DataContext = oList;
Binding binding = new Binding();
RightListBox.SetBinding(ListBox.ItemsSourceProperty, binding);
(RightListBox.ItemsSource as ObservableCollection<string>).Add(currentItemText);
if (toAddList != null)
{
toAddList.RemoveAt(currentItemIndex);
}
// Refresh data binding
ApplyDataBinding();
}
But the problem is that when I select an item from the left box, then click on add, it adds the new item into the right box but when I add a second item, it replaces the last one item that I added at the first step.
After that, the second problem is, how would be implemented the RemoveButton_Click ? Is it the same way as the previous method ?
You need not to do this much of code for this. Follow below given steps for more robust and maintainable approach.
Create two Observablecollection corresponding to left and right ListBox
Bind Observablecollection to ListBox
On Add button click, remove the item from observable collection assigned to left listbox and add to the oberservable collection binded to right grid.
You need not to update the bindings explicitly. Observable collection notify the collection changes automatically.
In code -
public ObservableCollection<ApplicationFormats> Formats { get; set; }
Xaml -
<ListBox Name="LeftListBox" ItemsSource="{Binding Formats}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have a Pivot control that uses an ItemsSource to bind to a list of ViewModel instances. I assign a custom ItemTemplateSelector to map between ViewModel types and DataTemplate definitions. This all works fine and the correct display is created for each ViewModel based on the associated DataTemplate. Something like this...
<Pivot ItemsSource="{x:Bind ViewModels}"
ItemTemplateSelector="{StaticResource ViewModelSelector}"
SelectedItem="{x:Bind SelectedViewModel, Mode=TwoWay}"/>
The problem is that I want to automatically set focus to a control within each page when that page is first shown. They are typically data entry forms and so the user currently has to select the first control to start entering data. It would be better if first showing a page automatically then set focus to a control on that page.
Any ideas?
You could bind a method to the TextBox when it's loaded.
For example:
<Pivot.ItemTemplate>
<DataTemplate x:DataType="local:Test">
<TextBox Text="{x:Bind Content}" Height="50" Loaded="{x:Bind TextBox_Loaded}">
</TextBox>
</DataTemplate>
</Pivot.ItemTemplate>
public void TextBox_Loaded(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
textBox.Focus(FocusState.Programmatic);
}
}
I am trying to make a form of sorts where the user will have the option to press a button to dynamically add more text boxes, with each text box to contain the path of a directory to exclude from a search. This is relatively trivial using code-behind, but my problem is doing it in proper MVVM.
The general markup for the structure is:
<ScrollViewer >
<StackPanel>
<DockPanel LastChildFill="False">
<TextBox DockPanel.Dock="Left"/>
<Button DockPanel.Dock="Right"
Content="+"/>
</DockPanel>
</StackPanel>
</ScrollViewer>
Clicking the button will add a new DockPanel with a TextBox and Button to the StackPanel. All buttons but the bottom-most will change to a minus sign. How can I somehow bind to the text of all the text boxes?
As an aside, once/if I get this working, would it be better to make it into its own component?
Quick pseudo-code to get you started:
cs (view model):
// INotifyPropertyChanged if you need, as well as full-properties with notification
public class Item
{
public string Text {get; set;}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
void OnCommandAdd() => Items.Add(new Item());
xaml (view):
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The idea is to use control able to display list (e.g. ItemsControl) and collection of items in view model. Adding new element to view is done by adding item to that collection.
All TextBoxes will have Text bound to corresponding property of item.
I'm developing a windows phone 8.1 app in XAML and C#. I have a ListView getting its Items from a bound list and displaying them through a DataTemplate. Now, in this DataTemplate there are multiple child elements, and when the user taps on an item in the list, I want to be able to determine what child element he actually touched. Depending on that, the app should either expand a view with more details inside the Item, or navigate to another page.
The ItemClick event handler of the ListView is ListView_ItemClick(object sender, ItemClickEventArgs e), and I thought e.OriginalSource would maybe give me the answer, but this just gave me the clicked ListItem.
I have yet to try if encapsulating the children with buttons and intercepting their click events would work, but I'm happy to try any alternative there might be for this.
I just found the solution myself. I set the ListView to SelectionMode="None" and IsItemClickEnabled="False", and then I added Tapped handlers for the individual child elements. Works just as I wanted.
I've got a TextBlock and an Image in one ListViewItem and have just used the Image_PointerPressed event. Doing that also fires the ItemClick event for the ListView so I disable it first, do the stuff I want, then re-enable the ItemClick event so that still fires when the TextBlock is pressed.
Code behind:
private async void imgDone_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// disable click event so it won't fire as well
lvwCouncils.IsItemClickEnabled = false;
// do stuff
MessageDialog m = new MessageDialog("User Details");
await m.ShowAsync();
// Re-enable the click event
lvwCouncils.IsItemClickEnabled = true;
}
Xaml:
<ListView x:Name="lvwCouncils" ItemClick="lvwCouncils_ItemClicked" IsItemClickEnabled="true" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock
Grid.Column="1"
Text="{Binding council_name}"
FontSize="24"
Margin="10,10,30,10"
/>
<Border Height="20" Width="20" Margin="10,10,0,10" >
<Image x:Name="imgDone"
Source="Assets/user_earth.png" Stretch="UniformToFill" PointerPressed="imgDone_PointerPressed"/>
</Border>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Use the SelectionChanged event.
Cast the sender object to ListView type and then retrieve the item from the SelectedItem property.
Similar question here but for a different control :
Get the index of the selected item in longlistselector
I'm assuming this is a simple thing that I am missing.
I have a ListBox in a WPF app that I am writing. Each row has a button to perform a simple action based on the row that the button is on. If the user clicks on the button directly then the SelectedItem on the ListBox is null. If I click in the row first, then click the button the SelectedItem is the row, as expected.
I want to be able to have the row that the button is on selected when the button is clicked. Again, I'm assuming that I am missing something simple, but my searches are coming up empty so far.
In case you want to select ListBoxItem on button click of ListBoxItem you can do this by attaching click handler to your button.
Assuming you have this XAML for ListBox declaration:
<ListBox x:Name="listBox" ItemsSource="{Binding SourceCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding PropertyName}" Click="Button_Click"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
you can select listBoxItem from handler:
private void Button_Click(object sender, RoutedEventArgs e)
{
ListBoxItem selectedItem = (ListBoxItem)listBox.ItemContainerGenerator.
ContainerFromItem(((Button)sender).DataContext);
selectedItem.IsSelected = true;
}
Access DataContext of button which will be same as that of ListBoxItem. Hence, with it you can get container element i.e. ListBoxItem from ItemContainerGenerator.
Set IsSelected to True on fetched listBoxItem.