I am writing a simple addressbook example application in WPF in which I have a listview that holds the contacts as User objects, but each item is represented with a TextBlock only showing the name.
What I want to achieve is that a user can drag the item onto a "group". Groups are presented on the left hand side of the window. It is a simple grid column with several TextBlock items.
My relevant codebehind:
/** Display Contact in the contact pane**/
private void lstItemContact_MouseDown(object sender, MouseButtonEventArgs e)
{
ListViewItem item = (ListViewItem)sender;
User selectedUser = (User) item.Content;
DragDrop.DoDragDrop(lstContacts, item, DragDropEffects.Move);
contactPane.Fullname = selectedUser.Name;
contactPane.Email = selectedUser.Mail;
}
private void tbFavouritesDrop_Drop(object sender, DragEventArgs e)
{
User dropped_user = (User)sender;
MessageBox.Show(dropped_user.Name);
}
And the XAML:
<ListView x:Name="lstContacts" Width="250" Grid.Row="1" Grid.Column="1">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock x:Name="lstItemContact" FontWeight="Bold" FontSize="14" Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="lstItemContact_MouseDown" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<TextBlock AllowDrop="True" Drop="tbFavouritesDrop_Drop" Name="tbFavouritesDrop">
<Border CornerRadius="3" Background="OrangeRed" Height="7" Width="7" VerticalAlignment="Center" Margin="0 0 2 5"/>
<Label FontFamily="Segoe UI Light" FontSize="14" Padding="0">Favourites</Label>
</TextBlock>
Once I drag the Item onto the "Favourites" Group I get the following error:
Additional information: Unable to cast object of type 'System.Windows.Controls.TextBlock' to type 'AddressBook1.User'
I am not sure what the exact problem is? Is the problem, that my listview item is a textblock ? The item I am sending is a User Object, and that reaches tbFavouritesDrop_Drop as well.
EDIT 1:
I have changed my Drop event handler to:
private void tbFavouritesDrop_Drop(object sender, DragEventArgs e)
{
TextBlock item = (TextBlock)sender;
MessageBox.Show(item.Text);
}
No exception is thrown, however, the .Text property is empty.
Ok, I found a solution after going crazy from another thread: WPF Drag and Drop - Get original source info from DragEventArgs
Which leaves me with:
/** Display Contact in the contact pane**/
private void lstItemContact_MouseDown(object sender, MouseButtonEventArgs e)
{
ListViewItem item = (ListViewItem)sender;
User selectedUser = (User) item.Content;
contactPane.Fullname = selectedUser.Name;
contactPane.Email = selectedUser.Mail;
}
private void lstItemContact_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (e.Source != null)
{
User selectedItem = (User) lstContacts.SelectedItem;
DragDrop.DoDragDrop(lstContacts, selectedItem, DragDropEffects.Move);
}
}
}
private void tbFavouritesDrop_Drop(object sender, DragEventArgs e)
{
User selectedUser = e.Data.GetData("AddressBook1.User") as User;
MessageBox.Show(selectedUser.Name);
}
I hope that helps someone else. The point here was to use e.Data.GetData("AddressBook1.User") and not work with the sender.
Related
I have a list view, of which the first column is checkboxes to enable/disable the item which represents said row. The problem is, when I change the checkbox, it does not select the row. Thus, when inside my checkBox checked/unchecked event I do listView.SelectedItem, it is null and crashes. Is there any way to fix this behavior so the listView check will select the item? Or, if there is an equivalent CheckedItems property in WPF like there is in WinForms?
XAML:
<Grid>
<ListView x:Name="listView1" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="375">
<ListView.View>
<GridView>
<GridViewColumn x:Name="StatusHeader" Header="Status" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="5, 0" IsChecked="{Binding loaded}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="NameHeader" Header="Name" Width="130" DisplayMemberBinding="{Binding name}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
C#:
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
module v = (module)listView1.SelectedItem; // crash
_client.AddClientModule(v.path);
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
module v = (module)listView1.SelectedItem; // crash
_client.RemoveClientModule(v.name);
}
You can use the DataContext to access the ViewModel and manually select it (if it is desired).
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
var cb = (CheckBox)sender;
var v = (module)cb.DataContext;
_client.AddClientModule(v.path);
// Select manually
listView1.SelectedItem = v;
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
var cb = (CheckBox)sender;
var v = (module)cb.DataContext;
_client.RemoveClientModule(v.path);
// Select manually
listView1.SelectedItem = v;
}
In Windows Universal app, I have a pivot table which every tab content have gridview, gridview items are multi select mode,
What I want that if any one item once checked (selected), then it unable to unselect(uncheck)
<Grid DataContext="{Binding Path=Value}">
<GridView x:Name="categoryItemsGV"
Margin="5,5,0,0"
SizeChanged="categoryItemsGV_SizeChanged"
IsItemClickEnabled="True"
ItemClick="categoryItemsGV_ItemClick"
SelectionMode="Single"
ItemsSource="{Binding}">
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<!--<Setter Property="VerticalContentAlignment" Value="Center"/>-->
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="195" Height="43" Margin="3">
<StackPanel Width="193" Height="40" Background="Gray" Opacity="0.5" HorizontalAlignment="Right" VerticalAlignment="Bottom" />
<StackPanel Orientation="Horizontal" Width="193" Height="40" Padding="7,7,0,0" Background="#FDFCC2" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock Text="{Binding ProductOptionLineName}" FontSize="18" MaxLines="1" TextTrimming="CharacterEllipsis" Visibility="{Binding Converter={StaticResource langToVisibilityConverter}, ConverterParameter='CH', Mode=OneWay}">
</TextBlock>
<TextBlock Text="{Binding ProductOptionLineNameEn}" FontSize="18" MaxLines="1" TextTrimming="CharacterEllipsis" Visibility="{Binding Converter={StaticResource langToVisibilityConverter}, ConverterParameter='EN', Mode=OneWay}"/>
<TextBlock Text="{Binding ExtraPriceString}" FontSize="18" Margin="2,0,0,0"></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
private async void categoryItemsGV_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ProductOptionLineModel;
}
We can use the SelectRange(ItemIndexRange) method to selects a block of items described by the ItemIndexRange.
When you call SelectRange(ItemIndexRange), all items in the specified range are selected, regardless of their original selection state. You can select all items in a collection by using an ItemIndexRange with a FirstIndex value of 0 and a Length value equal to the number of items in the collection.
For more info, see Remarks of the SelectRange(ItemIndexRange).
We can use the ItemClick to get which item is be clicked. Then we can add the SelectionChanged event and set the number of the clicked item to the SelectRange method.
For example:
private int number;
private void categoryItemsGV_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ProductOptionLineModel;
number = ProductOptionLineModels.IndexOf(item);
}
private void categoryItemsGV_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
categoryItemsGV.SelectRange(new ItemIndexRange(number, 1));
}
If we want to keep item selected as it was already selected, use below approach.
private async void categoryItemsGV_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ProductOptionLineModel;
GridView gv = sender as GridView;
gv.SelectedItems.Remove(item);
}
and if we want to keep item deselect on click (prevent deselected) for validation purpose. used below approach.
private async void categoryItemsGV_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ProductOptionLineModel;
await _viewModel.DialogService("FirstRequireMinOption", "", true);
GridView gv = sender as GridView;
gv.SelectedItems.Add(item);
}
I am trying to detect which item in a listview is focused, but I am not getting the events detected. I am developing for Xbox One UWP, so I cannot use mouse or keyboard events, only focus can be used.
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" GotFocus="StackPanel_GotFocus" >
<StackPanel Name="Imagestack" Orientation="Horizontal">
<Image Source="{Binding Image}" Height="144" Width="256" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
private void StackPanel_GotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Image focus");
Image img = sender as Image;
Bgimage.Source = img.Source;
}
You should register to the ListView.GotFocus event.
The OriginalSource from the event parameter will be the ListViewItem which has received the focus. You can then retrieve the item content using ListViewItem.Content.
XAML:
<ListView x:Name="list" GotFocus="list_GotFocus">
<ListView.ItemTemplate>...</ListView.ItemTemplate>
</ListView>
Code behind:
private void list_GotFocus(object sender, RoutedEventArgs e)
{
var focusedItem = (e.OriginalSource as ListViewItem)?.Content;
}
You don't need to get focus state to get data from the clicked ListViewItem, the ItemClick event of the ListView may be what you're looking for:
<ListView x:Name="LV_Items"
IsItemClickEnabled="True"
ItemClick="LV_Items_ItemClick"
>
</ListView>
private void LV_Items_ItemClick(object sender, ItemClickEventArgs e)
{
// Get instance of the model in the clicked ListViewItem
MyModel myModel = (MyModel)e.ClickedItem;
Image img = myModel.Image;
}
I am building a WPF application with MVVM architecture. In one form I have 2 listboxes and I want to perform filter based search. I am using a common search textbox, so I have to differentiate the search based on which listbox is selected. Please find my sample listbox below:
<HeaderedContentControl Header="Visible Objects:" Height="120" Width="250" Margin="20,20,20,0">
<ListBox Name="lstObjects" Height="100" Margin="5" ItemsSource="{Binding ProfileObjTypeToBind, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkbxVisibleObjects" Grid.Column="1"
Content="{Binding Path=Value}" IsChecked="{Binding Path=flag,Mode=TwoWay}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HeaderedContentControl>
<HeaderedContentControl Header="User Groups to View:" Height="120" Width="250" Margin="20,10,20,10">
<ListBox Name="lstGroups" Height="100" Margin="5" ItemsSource="{Binding ProfileUserGrpToBind, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="chkAllowedGroups" Content="{Binding Path=GroupName}"
IsChecked="{Binding Path=flag,Mode=TwoWay}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HeaderedContentControl>
All I want to do is identify the listbox selected and perform the filtering based on text entered in textbox. Please help me
Thanks a lot in advance.
You can't have a selected ListBox AND be able to write stuff to a TextBox. You can save the reference to your last ListBox though using SelectionChanged or some other method
private ListBox SelectedListBox = null;
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedListBox = (sender as ListBox);
}
once you have a reference to your last selected ListBox you can add TextChanged event to your TextBox:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (SelectedListBox == null)
return;
string searchText = (sender as TextBox).Text;
SelectedListBox.Items.Filter = (i) => { return ((string)i).Contains(searchText); }; // Or any other condition required
}
I created a LongListSelector with textblock and an image,then How do I tap the image to show selected item name in my list, and tap the item name to show messagebox? Below is my code to bind the name and image:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="TileDataTemplate">
<Grid Background="{StaticResource TransparentBrush}"
Margin="0, 0, 0, 12" Height="60">
<TextBlock Text="{Binding Name}" Margin="60, 10, 0, 0" FontSize="24" Height="60">
</TextBlock>
<Image x:Name="GetName" Tap="GetName_Tap" Grid.Column="0" Source="/Assets/AppBar/Delete.png" Height="40" Width="40"
Margin="0, 6, 0, 5" HorizontalAlignment="Right" VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector
SelectionChanged="MainLongListSelector_SelectionChanged"
Margin="10,6,0,0"
ItemsSource="{Binding Staff.Items}"
LayoutMode="Grid"
GridCellSize="400,80"
ItemTemplate="{StaticResource TileDataTemplate}"
/>
</Grid>
Code Behind:
private void MainLongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show("Hi");
}
private void GetName_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
LongListSelector selector = sender as LongListSelector;
StaffData data = selector.SelectedItem as StaffData;
MessageBox.Show(data.Name);
}
When I tap on textblock,the message "Hi" is displayed successful. But if I tap on image, I get the null value. How to I solve it? Thanks
sender isn't the LongListSelector but the image on which the user tapped, hence the null error.
Basically, you just want to retrieve the item on which the user has tapped? In that case, use the DataContext property of the tapped control to retrieve it:
private void GetName_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var element = (FrameworkElement)sender;
StaffData data = (StaffData)element.DataContext;
MessageBox.Show(data.Name);
}
(FrameworkElement is the base type of every UI control. Using that, you don't have to worry about whether it's an image, a textblock, ...)