Drag On ListView When ItemsTemplate is defined - c#

I am developing a UWP application and in one scenario I have to add Drag and drop feature on a ListView . But DragItemsStarting event doesn't get trigger when ItemsTemplate is defined.
In one scenario when I do Drag operation on ListViewItem by selecting its border it works well but when I do the drag on item it doesn't work.
Here is the Image for drag operation on items border:
Here is the XAML code:
<ListView Grid.Row="3"
ScrollViewer.IsScrollInertiaEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Enabled"
CanDragItems="True"
CanReorderItems="True"
ReorderMode="Enabled"
AllowDrop="True"
SelectionMode="Single"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
DragItemsStarting="{x:Bind VM.DragItemsStarting, Mode=OneWay}"
DragOver="{x:Bind VM.DragOver, Mode=OneWay}"
Drop="{x:Bind VM.DragDrop, Mode=OneWay}"
ItemsSource="{x:Bind ItemSource, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Model">
<Button HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Command="{Binding DataContext.PageCommand, ElementName=pageMain}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<TextBlock Text="{x:Bind ShowName,Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="Black"
TextWrapping="WrapWholeWords"
Margin="3" />
<ProgressBar Grid.Row="1"
Margin="0"
Value="25"
Height="8"
VerticalAlignment="Bottom"
Foreground="Green" />
</Grid>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
Is there any way I can perform drag operation on complete ListViewItem ?

You should avoid the use of Button directly inside ItemTemplate if you are having drag and drop features in your application, use a Grid or something else.
Now to enable click feature on ListItem set IsItemClickEnabled property to True and use ItemClick event on the ListView.

Related

How to get webview2 control in list control

I want to pass the webview2 control on the page to the ViewModel after clicking the button.
The following is part of the code for xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel>
<!--Click the button "Button_single", and the value of parameter can be obtained from ViewModel as Microsoft.Web.WebView2.Wpf.WebView2 type-->
<Button Command="{Binding BtnCommand1}" CommandParameter="{Binding ElementName=webView_single}">Button_single</Button>
<!--Click the button "Button_list", and the value of parameter obtained from ViewModel is null. Why?-->
<Button Command="{Binding BtnCommand1}" CommandParameter="{Binding ElementName=webView_list}">Button_list</Button>
<webview2:WebView2 Name="webView_single" Source="https://www.google.com/" Grid.Row="1">
<behaviour:Interaction.Triggers>
<behaviour:EventTrigger EventName="NavigationCompleted">
<behaviour:CallMethodAction TargetObject="{Binding}" MethodName="webView2_NavigationCompleted" />
</behaviour:EventTrigger>
</behaviour:Interaction.Triggers>
</webview2:WebView2>
</StackPanel>
<ScrollViewer Grid.Row="2" >
<ItemsControl Grid.Row="1" ItemsSource="{Binding AccountDtos}" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}" >
<Grid Width="600" MinHeight="800" MaxHeight="250" Margin="8" >
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border CornerRadius="4" Grid.RowSpan="5" Background="#7F7F7F" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="UserName:" />
<TextBlock Padding="5,0" Text="{Binding UserName}" />
<TextBlock Text="Password:" />
<TextBlock Padding="5,0" Text="{Binding Password}" />
</StackPanel>
<webview2:WebView2 Name="webView_list" Source="https://www.google.com/" Grid.Row="1">
<behaviour:Interaction.Triggers>
<behaviour:EventTrigger EventName="NavigationCompleted">
<behaviour:CallMethodAction TargetObject="{Binding}" MethodName="webView2_NavigationCompleted" />
</behaviour:EventTrigger>
</behaviour:Interaction.Triggers>
</webview2:WebView2>
</Grid>
</md:TransitioningContent>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
I want to pass the webview2 control on the page to the ViewModel after clicking the button.
The following is part of the code for xaml:
public DelegateCommand<object> BtnCommand1 { get => new DelegateCommand<object>(Execute1); }
private void Execute1(object parameter)
{
//In the xaml page, if you click the button "Button_single", you can get the parameter value of Microsoft.Web.WebView2.Wpf.WebView2 type
//If you click the button "Button_list", the value of parameter is null. Why and how can it not be null?
Console.Write(parameter);
}
I want to get the webView control in the list control in the ViewModel. How should I write this code?
(This question Passing a Different button in Command Parameter Wpf Similar to my question, but different)
There are two reasons the webView_list commandparameter cannot work.
The first is conceptual. There are going to be a list of those WebView2s rather than just one. How's it supposed to know which one it is to reference?
You know if you have a list of anything in c# then you'd have to reference by index or something which one in the list you want.
The same would be true for xaml. You'd need to tell it to go look at row 0 or 1 or 2 or whatever.
There is another complication though. WPF has the concept of namescopes. All the controls directly in the grid of your window are in the same namescope.
When you have templates and in particular lists of things that becomes a bit more complicated.
Let's think about this from the bottom up though.
You've named a control webView_list. This is in an itemtemplate. So when you have 4 items you will have 4 WebView2s. But it will not error. Somehow those 4 named controls do not collide with one another.
This is because each of those items produced from that itemtemplate have their own namescope. The first item has a namescope of it's own, the second has it's own namescope etc.
You cannot just use elementname to reference something in a different namescope. So you can't get at a specific webview2 in that list using elementname from outside the item it's in.
In any case, you need some way to tell which item.
You could use selecteditem if this was a listbox.
An itemscontrol has no selection though. To get at your webview2 in an item the usual thing to do would be to put the button in the itemtemplate and the same namescope. That could then use relativesource to get to the command in the parent datacontext. Something like:
<ItemsControl.ItemTemplate>
<DataTemplate>
<md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}" >
<Grid Width="600" MinHeight="800" MaxHeight="250" Margin="8" >
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border CornerRadius="4" Grid.RowSpan="5" Background="#7F7F7F" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="UserName:" />
<TextBlock Padding="5,0" Text="{Binding UserName}" />
<TextBlock Text="Password:" />
<TextBlock Padding="5,0" Text="{Binding Password}" />
</StackPanel>
<Button Command="{Binding DataContext.BtnCommand1, RelativeSource={RelativeSource AncestorType ItemsControl}}"
CommandParameter="{Binding ElementName=webView_list}" Grid.Row="2">Button_list</Button>
<webview2:WebView2 Name="webView_list" Source="https://www.google.com/" Grid.Row="2">
<behaviour:Interaction.Triggers>
<behaviour:EventTrigger EventName="NavigationCompleted">
<behaviour:CallMethodAction TargetObject="{Binding}" MethodName="webView2_NavigationCompleted" />
</behaviour:EventTrigger>
</behaviour:Interaction.Triggers>
</webview2:WebView2>
</Grid>
</md:TransitioningContent>
</DataTemplate>
</ItemsControl.ItemTemplate>

Expand grid cells but stop at contents of listBox

I have a WPF form with some text fields and two ListBoxes:
<TextBlock>Label</TextBlock>
<TextBox Text="{Binding Input}"/>
<TextBlock>List Label</TextBlock>
<ListBox ItemsSource="{Binding Items1}"/>
<TextBlock>Second List Label</TextBlock>
<ListBox ItemsSource="{Binding Items2}"/>
I'd like for the two ListBoxes to expand vertically to fit their container, but for each one to stop expanding once its scrollbar is no longer necessary. The closest I've come is with a grid:
<Grid VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="40" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="40" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock>Label</TextBlock>
<TextBox Text="{Binding Input}"/>
<TextBlock>List Label</TextBlock>
</StackPanel>
<ListBox Grid.Row="1" ItemsSource="{Binding Items1}"/>
<TextBlock Grid.Row="2">Second List Label</TextBlock>
<ListBox Grid.Row="3" ItemsSource="{Binding Items2}"/>
</Grid>
However, then the space taken up by the list boxes is always the same due to the asterisk row height, so if one list stops growing, the remainder of the height to match the other list is left as empty space at the bottom of the grid.
What you want is a DockPanel...
<DockPanel >
<TextBlock DockPanel.Dock="Top">Label</TextBlock>
<TextBox Text="{Binding Input}" DockPanel.Dock="Top"/>
<TextBlock DockPanel.Dock="Top">List Label</TextBlock>
<ListBox Grid.Row="1" ItemsSource="{Binding Items1}" DockPanel.Dock="Top" MinHeight="40" MaxHeight="200"/>
<TextBlock Grid.Row="2" DockPanel.Dock="Top">Second List Label</TextBlock>
<ListBox Grid.Row="1" ItemsSource="{Binding Items2}" MinHeight="40"/>
</DockPanel>
This fulfills all of your requirement. The container is completely filled. The listboxes stop expanding when scrollbars are no longer needed. However if there are too many items in the 1st listbox the 2nd one will disappear completely. This is why I put in a max height for the first list box.

how to access TextBox inside ListBox itemsSource which is Datatemplate?

I have a ListBox and its ItemsSource is linked with a ComboBox SelectedItem. Its template is associated with a DataTemplate. Everything is fine but how to access each TextBox inside ListBoxItems. I have 5 labels and 2 TextBoxes inside each ListItem. I want to access each and every TextBox and labels inside ListBoxItem. I need some idea how to access each TextBox inside each Item. For example, there is "wbprofileDesc" TextBox in first ListBoxItem. So I need to access this TextBox and write some functionality to it like keypress event. It need to work for each and every TextBox inside all the ListBoxItems individually. Assume there are 5 ListBoxItems. Also I need to fetch other controls also like wbselect(ComboBox), wbdepth, wbwidthvalue and etc. I am using MVVM model for this.
<Window.Resources>
<local:wbItemViewModel x:Key="wbItem"/>
<DataTemplate x:Key="wbObjectsDataTemplate">
<Grid Grid.ColumnSpan="1" Grid.RowSpan="1" Height="Auto" Width="642" Margin="0,0,0,-14">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="697" Margin="10,0,0,0" Height="54" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="49*"/>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="309*"/>
<ColumnDefinition Width="306*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition/>
<RowDefinition Height="auto" MinHeight="5"/>
</Grid.RowDefinitions>
<Label Content="{Binding WBName_lbl}" Margin="0,3,0,5" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"/>
<ComboBox x:Name="wbselect" Margin="5,0,10,1" Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="0">
<ComboBoxItem x:Name="wbstraight" IsSelected="True" Content="straight"/>
<ComboBoxItem x:Name="wbtapered" Content="tapered"/>
</ComboBox>
<!--KeyDown="{Binding Path=profileDesc}"-->
<!-- KeyDown="profileDesc_KeyDown" -->
<TextBox x:Name="wbprofileDesc" Margin="18,0,20,1" Grid.Column="2" Grid.Row="0" GotFocus="wbprofileDesc_GotFocus"/>
<TextBox x:Name="wbdepth" Text="{Binding ElementName=wbwidthvalue, Path=Content, Mode=OneWay}" Margin="10,0,73,1" Grid.Column="3" Grid.Row="0"/>
<Label x:Name="wbwidthvalue" Margin="10,0,190,5" Grid.Column="2" FontSize="8" Grid.Row="1"/>
<Label x:Name="wbthicknessvalue" Margin="118,0,82,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wblengthvalue" Margin="208,0,0,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wbnexwidthvalue" Margin="10,0,178,5" FontSize="8" Grid.Row="1" Grid.Column="3"/>
<Label x:Name="wbdepthvalue" Grid.Row="1" Grid.Column="3" FontSize="8" Margin="132,0,31,5"/>
<!--<Label x:Name="totalvalue" Margin="30,10,24,16" Grid.Row="3" Grid.Column="3"/>-->
</Grid>
</Grid>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="wbListDataTemplate"
ItemsSource="{Binding wbVisibleItems}"
ItemTemplate="{DynamicResource wbObjectsDataTemplate}"
DataContext="{DynamicResource wbItem}"
Background="{x:Null}"
SelectedItem="{Binding wbSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True"
Canvas.Top="51" Height="222" Width="686"/>
Here is an example of you could find the controls in the DataTemplate inside the event handler:
private void wbprofileDesc_GotFocus(object sender, RoutedEventArgs e)
{
TextBox wbprofileDesc = sender as TextBox;
Grid parentGrid = wbprofileDesc.Parent as Grid;
ComboBox wbselect = parentGrid.Children.OfType<ComboBox>().FirstOrDefault(x => x.Name == "wbselect");
Label wbwidthvalue = parentGrid.Children.OfType<Label>().FirstOrDefault(x => x.Name == "wbwidthvalue");
}

Checkbox in ItemTemplate

I have a <Checkbox/> in my <GridView.ItemTemplate>. How do I handle the <Checkbox/> as to the element in which it is?
For example, I want to delete item when checkbox checked.
I think should write here. But what?
private void CheckBox_Checked_1(object sender, RoutedEventArgs e)
{
}
Here's My XAML:
<GridView Margin="0,10,0,0"
RelativePanel.AlignHorizontalCenterWithPanel="True"
x:Name="GridColections"
IsItemClickEnabled="True"
SelectionMode="None"
ItemsSource="{x:Bind DS.AllRem, Mode=OneWay}"
ItemClick="GridColections_ItemClick" >
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:GetRem" >
<Grid Margin="-2,0,-6,0" BorderBrush="LightGray" BorderThickness="1" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="{x:Bind ReminderName}" Margin="5,5,0,0" FontSize="20"/>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="1" Width="600" TextWrapping="Wrap" Text="{x:Bind ReminderDescription}" Margin="5,5,0,0" FontSize="12"/>
<CheckBox Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Center" Checked="CheckBox_Checked_1"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The problem is that you almost certainly want to be able to use the DataContext in your click handler but you won't get that easily by just having a reference to the CheckBox which will be the sender argument in your callback. Normally what you would do here is create a Command on your item's view model and bind to that and any additional information that you would want to pass in you would pass in through the CheckBox's CommandParameter.
Once you do this you are now operating in your view model with a reference to whatever piece of information that you need through the command parameter (for instance you could set CommandParameter = "{Binding}" to pick up the entire data context which would be the item's view model and that would be accessible from your Command as an argument to it). You should be able to solve your issue this way.

Stackpanel: Black background on wp8

I have one problem - my stackpanel is vey big and it breaks(background color is changed to black).. What should i do to improve it?
<Grid x:Name="LayoutRoot" Background="#FF2D2D2D" >
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Orientation="Horizontal" Grid.Row="0">
..
</StackPanel>
<ScrollViewer Name="viewer" Grid.Row="1" >
<StackPanel Name="ContentGrid" Canvas.ZIndex="1" Margin="0, 0,0,80" Background="White" Width="452">
<Image Name="ImageImage" Height="300" VerticalAlignment="Top"/>
<TextBlock Name="DateText" TextWrapping="Wrap" TextAlignment="Center" FontSize="18" Foreground="Black"/>
<TextBlock Name="TitleText" TextWrapping="Wrap" FontSize="20" TextAlignment="Center" Foreground="Black" Margin="10,0"/>
<TextBlock TextWrapping="Wrap" Margin="10,15,10,2" Name="DescroptionText" FontSize="23" Foreground="#FF494949" FontFamily="Portable User Interface"/>
<TextBlock TextWrapping="Wrap" TextTrimming="WordEllipsis" Margin="10,0,10,2" Name="DescroptionText2" FontSize="23" Foreground="#FF494949"/>
<ListBox SelectionChanged="GridImages_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Disabled" Name="GridImages" ItemTemplate="{StaticResource AttachmentsItemTemlate}" Grid.RowSpan="2" FontFamily="Portable User Interface" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" FlowDirection="LeftToRight" ItemWidth="150" ItemHeight="150"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</ScrollViewer>
</Grid>
There is a limitation of 2048px in Windows Phone UIElements.
You should try to break your different elements into smaller elements (for example: you could put several stackpanels inside the first one).
In TextBox elements there is a workaround explained here.
Best this is to make the Main Window to white background and Make your stackpanel as transparent background instead of giving any color to it. It works great as I have tested it.
Try this code, but first you need to add windows toolkit library.
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
<toolkit:PhoneTextBox
TextWrapping="Wrap"
Name="txtString"
ScrollViewer.VerticalScrollBarVisibility="Visible"
MaxHeight="200"
PlaceholderText="Add text"
Padding="5"
Width="370"
FontFamily="Open Sans Light"
FontSize="22"
Height="Auto" ///Use Auto or provide height value
Margin="10"
/>
This code is used for Scrolling as well work for Auto Growing Textbox. If you don't want Auto Growing Textbox then provide height instead of Auto in Height attribute.

Categories